diff --git a/README.md b/README.md index 2ffc389..4c59d03 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,16 @@ # ctru-rs -A Rust wrapper library for smealum's -[ctrulib](https://github.com/smealum/ctrulib). Intended for use only when -targeting CTR. +A Rust wrapper library for smealum's [ctrulib](https://github.com/smealum/ctrulib). -## How to build +See the [3DS project template](https://github.com/rust3ds/rust3ds-template) for instructions on how to use this library. -1. Install the devkitARM toolchain for your system. Make sure `DEVKITPRO` is - set in your environment. -2. Modify ~/.cargo/config and add the following lines: +## Structure -```toml - [target.3ds] - ar = "/path/to/arm-none-eabi-ar" -``` - -3. Build with `cargo build --target 3ds.json`. -4. A dkA linkable .rlib (static library) will be generated. Read below for -instructions on using. - -## How to use - -You can build your homebrew projects through Cargo just as easily as any other -platform. Add this to your `Cargo.toml`: - -```toml - [dependencies.ctru-rs] - git="https://github.com/rust3ds/ctru-rs" -``` - -**It is highly recommended to use the [template -project.](https://github.com/rust3ds/rust3ds-template)** - -## Contributing - -PR's are welcome. Organization of rust specific features and wrapper -functionality has not been decided on yet. +This repository is organized as follows: +* `ctru-rs`: Safe, idiomatic wrapper around `ctru-sys`. +* `ctru-sys`: Low-level, unsafe bindings to ctrulib +* `ctr-std`: A partial implementation of the Rust standard library for the 3DS. +* `ctr-libc`: C types and functions used by ctru-sys and ctr-std. ## License @@ -66,3 +41,4 @@ applies to every file in the tree, unless otherwise noted. Rust is primarily distributed under the terms of both the MIT license and the Apache License (Version 2.0), with portions covered by various BSD-like licenses. See [LICENSE-APACHE](https://github.com/rust-lang/rust/blob/master/LICENSE-APACHE), [LICENSE-MIT](https://github.com/rust-lang/rust/blob/master/LICENSE-MIT), and [COPYRIGHT](https://github.com/rust-lang/rust/blob/master/COPYRIGHT) for details. + diff --git a/build.rs b/build.rs deleted file mode 100644 index 6b07e4e..0000000 --- a/build.rs +++ /dev/null @@ -1,36 +0,0 @@ -use std::env; -use std::path::PathBuf; -use std::fs; - -use std::option::Option::{self, Some, None}; - -const ENV_DKP: &'static str = "CTRULIB"; - -fn find_libctru() -> Option { - if let Ok(value) = env::var(ENV_DKP) { - let mut path = PathBuf::from(value); - path.push("lib"); - // metadata returns Err if the dir does not exist - if let Ok(metadata) = fs::metadata(path.as_path()) { - if metadata.is_dir() { - return Some(path); - } - } - } - return None; -} - -fn main() { - if let Some(path) = find_libctru() { - if let Some(s) = path.to_str() { - println!("cargo:rustc-link-lib=static=ctru"); - println!("cargo:rustc-link-search=native={}", s); - } else { - println!("path is not a valid string"); - std::process::exit(1); - } - } else { - println!("could not find libctru"); - std::process::exit(1); - } -} 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..50ead9d --- /dev/null +++ b/ctr-libc/src/lib.rs @@ -0,0 +1,177 @@ +// 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)] + +#![no_std] + +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/3ds.json b/ctr-std/3ds.json similarity index 88% rename from 3ds.json rename to ctr-std/3ds.json index fbdf65d..bdd5caa 100644 --- a/3ds.json +++ b/ctr-std/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", @@ -25,8 +26,6 @@ "-lc", "-lm", "-lsysbase", - "-lc", - "-lgcc", "-lc" ] } diff --git a/ctr-std/Cargo.toml b/ctr-std/Cargo.toml new file mode 100644 index 0000000..d4394a8 --- /dev/null +++ b/ctr-std/Cargo.toml @@ -0,0 +1,16 @@ +[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.ctr-libc] +path = "../ctr-libc" + +[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..15ee4b9 --- /dev/null +++ b/ctr-std/README.md @@ -0,0 +1,5 @@ +A work-in-progress port of the Rust Standard Library for the Nintendo 3DS, based on [ctrulib](https://github.com/smealum/ctrulib/) and the [devkitARM](http://devkitPro.org) toolchain. + +## Structure + +This library aims to mimick the Rust standard library's public interface as closely as possible, exposing functionality that is common between the 3DS and other platforms. System-specific functionality such as control input, save file management, GPU features, and so forth are implemented in `ctru-rs`. diff --git a/ctr-std/Xargo.toml b/ctr-std/Xargo.toml new file mode 100644 index 0000000..dc3fd74 --- /dev/null +++ b/ctr-std/Xargo.toml @@ -0,0 +1,5 @@ +[dependencies.collections] + +[dependencies.ctr-libc] +path = "../ctr-libc" +stage = 1 diff --git a/src/ascii.rs b/ctr-std/src/ascii.rs similarity index 94% rename from src/ascii.rs rename to ctr-std/src/ascii.rs index 93f447b..a063b85 100644 --- a/src/ascii.rs +++ b/ctr-std/src/ascii.rs @@ -10,9 +10,11 @@ //! Operations on ASCII strings and characters. -use core::mem; -use core::ops::Range; -use collections::{String, Vec}; +#![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. /// @@ -36,8 +38,10 @@ use collections::{String, Vec}; /// 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. @@ -53,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. @@ -71,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. @@ -89,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. @@ -110,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. @@ -127,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. @@ -144,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; @@ -187,6 +198,7 @@ impl AsciiExt for str { } } +#[stable(feature = "rust1", since = "1.0.0")] impl AsciiExt for [u8] { type Owned = Vec; #[inline] @@ -229,6 +241,7 @@ impl AsciiExt for [u8] { } } +#[stable(feature = "rust1", since = "1.0.0")] impl AsciiExt for u8 { type Owned = u8; #[inline] @@ -247,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] @@ -285,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], @@ -315,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), @@ -337,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, @@ -431,8 +453,7 @@ static ASCII_UPPERCASE_MAP: [u8; 256] = [ #[cfg(test)] mod tests { use super::*; - use rustc_unicode::char::from_u32; - use collections::string::ToString; + use char::from_u32; #[test] fn test_is_ascii() { @@ -447,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/ctr-std/src/error.rs b/ctr-std/src/error.rs new file mode 100644 index 0000000..454fa47 --- /dev/null +++ b/ctr-std/src/error.rs @@ -0,0 +1,497 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Traits for working with Errors. +//! +//! # The `Error` trait +//! +//! `Error` is a trait representing the basic expectations for error values, +//! i.e. values of type `E` in [`Result`]. At a minimum, errors must provide +//! a description, but they may optionally provide additional detail (via +//! [`Display`]) and cause chain information: +//! +//! ``` +//! use std::fmt::Display; +//! +//! trait Error: Display { +//! fn description(&self) -> &str; +//! +//! fn cause(&self) -> Option<&Error> { None } +//! } +//! ``` +//! +//! The [`cause`] method is generally used when errors cross "abstraction +//! boundaries", i.e. when a one module must report an error that is "caused" +//! by an error from a lower-level module. This setup makes it possible for the +//! high-level module to provide its own errors that do not commit to any +//! particular implementation, but also reveal some of its implementation for +//! debugging via [`cause`] chains. +//! +//! [`Result`]: ../result/enum.Result.html +//! [`Display`]: ../fmt/trait.Display.html +//! [`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 +// were scattered about. However, coherence objected to this +// arrangement, because to create the blanket impls for `Box` required +// knowing that `&str: !Error`, and we have no means to deal with that +// sort of conflict just now. Therefore, for the time being, we have +// moved the `Error` trait into libstd. As we evolve a sol'n to the +// coherence challenge (e.g., specialization, neg impls, etc) we can +// reconsider what crate these items belong in. + +use any::TypeId; +use cell; +use char; +use fmt::{self, Debug, Display}; +use mem::transmute; +use num; +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 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 + /// + /// ``` + /// use std::error::Error; + /// + /// match "xc".parse::() { + /// Err(e) => { + /// println!("Error: {}", e.description()); + /// } + /// _ => println!("No error"), + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn description(&self) -> &str; + + /// The lower-level cause of this error, if any. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::fmt; + /// + /// #[derive(Debug)] + /// struct SuperError { + /// side: SuperErrorSideKick, + /// } + /// + /// impl fmt::Display for SuperError { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// write!(f, "SuperError is here!") + /// } + /// } + /// + /// impl Error for SuperError { + /// fn description(&self) -> &str { + /// "I'm the superhero of errors!" + /// } + /// + /// fn cause(&self) -> Option<&Error> { + /// Some(&self.side) + /// } + /// } + /// + /// #[derive(Debug)] + /// struct SuperErrorSideKick; + /// + /// impl fmt::Display for SuperErrorSideKick { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// write!(f, "SuperErrorSideKick is here!") + /// } + /// } + /// + /// impl Error for SuperErrorSideKick { + /// fn description(&self) -> &str { + /// "I'm SuperError side kick!" + /// } + /// } + /// + /// fn get_super_error() -> Result<(), SuperError> { + /// Err(SuperError { side: SuperErrorSideKick }) + /// } + /// + /// fn main() { + /// match get_super_error() { + /// Err(e) => { + /// println!("Error: {}", e.description()); + /// println!("Caused by: {}", e.cause().unwrap()); + /// } + /// _ => println!("No error"), + /// } + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn cause(&self) -> Option<&Error> { None } + + /// Get the `TypeId` of `self` + #[doc(hidden)] + #[unstable(feature = "error_type_id", + reason = "unclear whether to commit to this public implementation detail", + issue = "27745")] + fn type_id(&self) -> TypeId where Self: 'static { + TypeId::of::() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, E: Error + 'a> From for Box { + fn from(err: E) -> Box { + Box::new(err) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, E: Error + Send + Sync + 'a> From for Box { + fn from(err: E) -> Box { + Box::new(err) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl From for Box { + fn from(err: String) -> Box { + #[derive(Debug)] + struct StringError(String); + + impl Error for StringError { + fn description(&self) -> &str { &self.0 } + } + + impl Display for StringError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.0, f) + } + } + + Box::new(StringError(err)) + } +} + +#[stable(feature = "string_box_error", since = "1.7.0")] +impl From for Box { + fn from(str_err: String) -> Box { + let err1: Box = From::from(str_err); + let err2: Box = err1; + err2 + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, 'b> From<&'b str> for Box { + fn from(err: &'b str) -> Box { + From::from(String::from(err)) + } +} + +#[stable(feature = "string_box_error", since = "1.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) + } + + fn cause(&self) -> Option<&Error> { + Error::cause(&**self) + } +} + +#[stable(feature = "fmt_error", since = "1.11.0")] +impl Error for fmt::Error { + fn description(&self) -> &str { + "an error occurred when formatting an argument" + } +} + +#[stable(feature = "try_borrow", since = "1.13.0")] +impl Error for cell::BorrowError { + fn description(&self) -> &str { + "already mutably borrowed" + } +} + +#[stable(feature = "try_borrow", since = "1.13.0")] +impl Error for cell::BorrowMutError { + fn description(&self) -> &str { + "already borrowed" + } +} + +#[unstable(feature = "try_from", issue = "33417")] +impl Error for char::CharTryFromError { + fn description(&self) -> &str { + "converted integer out of range for `char`" + } +} + +// 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 + let t = TypeId::of::(); + + // Get TypeId of the type in the trait object + let boxed = self.type_id(); + + // Compare both TypeIds on equality + t == boxed + } + + /// Returns some reference to the boxed value if it is of type `T`, or + /// `None` if it isn't. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn downcast_ref(&self) -> Option<&T> { + if self.is::() { + unsafe { + Some(&*(self as *const Error as *const T)) + } + } else { + None + } + } + + /// Returns some mutable reference to the boxed value if it is of type `T`, or + /// `None` if it isn't. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn downcast_mut(&mut self) -> Option<&mut T> { + if self.is::() { + unsafe { + Some(&mut *(self as *mut Error as *mut T)) + } + } else { + None + } + } +} + +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) + } +} + +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) + } +} + +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::() { + unsafe { + let raw: *mut Error = Box::into_raw(self); + Ok(Box::from_raw(raw as *mut T)) + } + } else { + Err(self) + } + } +} + +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> { + let err: Box = self; + ::downcast(err).map_err(|s| unsafe { + // reapply the Send marker + transmute::, Box>(s) + }) + } +} + +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> { + let err: Box = self; + ::downcast(err).map_err(|s| unsafe { + // reapply the Send+Sync marker + transmute::, Box>(s) + }) + } +} + +#[cfg(test)] +mod tests { + use super::Error; + use fmt; + + #[derive(Debug, PartialEq)] + struct A; + #[derive(Debug, PartialEq)] + struct B; + + impl fmt::Display for A { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "A") + } + } + impl fmt::Display for B { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "B") + } + } + + impl Error for A { + fn description(&self) -> &str { "A-desc" } + } + impl Error for B { + fn description(&self) -> &str { "A-desc" } + } + + #[test] + fn downcasting() { + let mut a = A; + let mut a = &mut a as &mut (Error + 'static); + assert_eq!(a.downcast_ref::(), Some(&A)); + assert_eq!(a.downcast_ref::(), None); + assert_eq!(a.downcast_mut::(), Some(&mut A)); + assert_eq!(a.downcast_mut::(), None); + + let a: Box = Box::new(A); + match a.downcast::() { + Ok(..) => panic!("expected error"), + Err(e) => assert_eq!(*e.downcast::().unwrap(), A), + } + } +} diff --git a/ctr-std/src/f32.rs b/ctr-std/src/f32.rs new file mode 100644 index 0000000..7a676c0 --- /dev/null +++ b/ctr-std/src/f32.rs @@ -0,0 +1,1871 @@ +// 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. + +//! The 32-bit floating point type. +//! +//! *[See also the `f32` primitive type](../primitive.f32.html).* + +#![stable(feature = "rust1", since = "1.0.0")] +#![allow(missing_docs)] + +#[cfg(not(test))] +use core::num; +#[cfg(not(test))] +use intrinsics; +#[cfg(not(test))] +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 libc::{c_float, c_int}; + + 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; + pub fn expm1f(n: c_float) -> c_float; + pub fn fdimf(a: c_float, b: c_float) -> c_float; + pub fn fmaxf(a: c_float, b: c_float) -> c_float; + pub fn fminf(a: c_float, b: c_float) -> c_float; + pub fn fmodf(a: c_float, b: c_float) -> c_float; + pub fn ilogbf(n: c_float) -> c_int; + pub fn logbf(n: c_float) -> c_float; + pub fn log1pf(n: c_float) -> c_float; + pub fn modff(n: c_float, iptr: &mut c_float) -> c_float; + pub fn nextafterf(x: c_float, y: c_float) -> c_float; + pub fn tgammaf(n: c_float) -> c_float; + + #[cfg_attr(all(windows, target_env = "msvc"), link_name = "__lgammaf_r")] + pub fn lgammaf_r(n: c_float, sign: &mut c_int) -> c_float; + #[cfg_attr(all(windows, target_env = "msvc"), link_name = "_hypotf")] + pub fn hypotf(x: c_float, y: c_float) -> c_float; + } + + // See the comments in the `floor` function for why MSVC is special + // here. + #[cfg(not(target_env = "msvc"))] + extern { + pub fn acosf(n: c_float) -> c_float; + pub fn asinf(n: c_float) -> c_float; + pub fn atan2f(a: c_float, b: c_float) -> c_float; + pub fn atanf(n: c_float) -> c_float; + pub fn coshf(n: c_float) -> c_float; + pub fn frexpf(n: c_float, value: &mut c_int) -> c_float; + pub fn ldexpf(x: c_float, n: c_int) -> c_float; + pub fn sinhf(n: c_float) -> c_float; + pub fn tanf(n: c_float) -> c_float; + pub fn tanhf(n: c_float) -> c_float; + } + + #[cfg(target_env = "msvc")] + pub use self::shims::*; + #[cfg(target_env = "msvc")] + mod shims { + use libc::{c_float, c_int}; + + #[inline] + pub unsafe fn acosf(n: c_float) -> c_float { + f64::acos(n as f64) as c_float + } + + #[inline] + pub unsafe fn asinf(n: c_float) -> c_float { + f64::asin(n as f64) as c_float + } + + #[inline] + pub unsafe fn atan2f(n: c_float, b: c_float) -> c_float { + f64::atan2(n as f64, b as f64) as c_float + } + + #[inline] + pub unsafe fn atanf(n: c_float) -> c_float { + f64::atan(n as f64) as c_float + } + + #[inline] + pub unsafe fn coshf(n: c_float) -> c_float { + f64::cosh(n as f64) as c_float + } + + #[inline] + #[allow(deprecated)] + pub unsafe fn frexpf(x: c_float, value: &mut c_int) -> c_float { + let (a, b) = f64::frexp(x as f64); + *value = b as c_int; + a as c_float + } + + #[inline] + #[allow(deprecated)] + pub unsafe fn ldexpf(x: c_float, n: c_int) -> c_float { + f64::ldexp(x as f64, n as isize) as c_float + } + + #[inline] + pub unsafe fn sinhf(n: c_float) -> c_float { + f64::sinh(n as f64) as c_float + } + + #[inline] + pub unsafe fn tanf(n: c_float) -> c_float { + f64::tan(n as f64) as c_float + } + + #[inline] + pub unsafe fn tanhf(n: c_float) -> c_float { + f64::tanh(n as f64) as c_float + } + } +} + +#[cfg(not(test))] +#[lang = "f32"] +impl f32 { + /// Returns `true` if this value is `NaN` and false otherwise. + /// + /// ``` + /// use std::f32; + /// + /// let nan = f32::NAN; + /// let f = 7.0_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) } + + /// Returns `true` if this value is positive infinity or negative infinity and + /// false otherwise. + /// + /// ``` + /// use std::f32; + /// + /// let f = 7.0f32; + /// let inf = f32::INFINITY; + /// let neg_inf = f32::NEG_INFINITY; + /// let nan = f32::NAN; + /// + /// assert!(!f.is_infinite()); + /// assert!(!nan.is_infinite()); + /// + /// 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) } + + /// Returns `true` if this number is neither infinite nor `NaN`. + /// + /// ``` + /// use std::f32; + /// + /// let f = 7.0f32; + /// let inf = f32::INFINITY; + /// let neg_inf = f32::NEG_INFINITY; + /// let nan = f32::NAN; + /// + /// assert!(f.is_finite()); + /// + /// assert!(!nan.is_finite()); + /// 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) } + + /// Returns `true` if the number is neither zero, infinite, + /// [subnormal][subnormal], or `NaN`. + /// + /// ``` + /// use std::f32; + /// + /// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32 + /// let max = f32::MAX; + /// let lower_than_min = 1.0e-40_f32; + /// let zero = 0.0_f32; + /// + /// assert!(min.is_normal()); + /// assert!(max.is_normal()); + /// + /// assert!(!zero.is_normal()); + /// assert!(!f32::NAN.is_normal()); + /// assert!(!f32::INFINITY.is_normal()); + /// // Values between `0` and `min` are Subnormal. + /// 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) } + + /// 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 + /// predicate instead. + /// + /// ``` + /// use std::num::FpCategory; + /// use std::f32; + /// + /// let num = 12.4_f32; + /// let inf = f32::INFINITY; + /// + /// 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) } + + /// Returns the mantissa, base 2 exponent, and sign as integers, respectively. + /// The original number can be recovered by `sign * mantissa * 2 ^ exponent`. + /// The floating point encoding is documented in the [Reference][floating-point]. + /// + /// ``` + /// #![feature(float_extras)] + /// + /// use std::f32; + /// + /// let num = 2.0f32; + /// + /// // (8388608, -22, 1) + /// let (mantissa, exponent, sign) = num.integer_decode(); + /// let sign_f = sign as f32; + /// let mantissa_f = mantissa as f32; + /// let exponent_f = num.powf(exponent as f32); + /// + /// // 1 * 8388608 * 2^(-22) == 2 + /// let abs_difference = (sign_f * mantissa_f * exponent_f - num).abs(); + /// + /// 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) { + num::Float::integer_decode(self) + } + + /// Returns the largest integer less than or equal to a number. + /// + /// ``` + /// let f = 3.99_f32; + /// let g = 3.0_f32; + /// + /// assert_eq!(f.floor(), 3.0); + /// assert_eq!(g.floor(), 3.0); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn floor(self) -> f32 { + // On MSVC LLVM will lower many math intrinsics to a call to the + // corresponding function. On MSVC, however, many of these functions + // aren't actually available as symbols to call, but rather they are all + // `static inline` functions in header files. This means that from a C + // perspective it's "compatible", but not so much from an ABI + // perspective (which we're worried about). + // + // The inline header functions always just cast to a f64 and do their + // operation, so we do that here as well, but only for MSVC targets. + // + // Note that there are many MSVC-specific float operations which + // redirect to this comment, so `floorf` is just one case of a missing + // function on MSVC, but there are many others elsewhere. + #[cfg(target_env = "msvc")] + return (self as f64).floor() as f32; + #[cfg(not(target_env = "msvc"))] + return unsafe { intrinsics::floorf32(self) }; + } + + /// Returns the smallest integer greater than or equal to a number. + /// + /// ``` + /// let f = 3.01_f32; + /// let g = 4.0_f32; + /// + /// assert_eq!(f.ceil(), 4.0); + /// assert_eq!(g.ceil(), 4.0); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn ceil(self) -> f32 { + // see notes above in `floor` + #[cfg(target_env = "msvc")] + return (self as f64).ceil() as f32; + #[cfg(not(target_env = "msvc"))] + return unsafe { intrinsics::ceilf32(self) }; + } + + /// Returns the nearest integer to a number. Round half-way cases away from + /// `0.0`. + /// + /// ``` + /// let f = 3.3_f32; + /// let g = -3.3_f32; + /// + /// assert_eq!(f.round(), 3.0); + /// assert_eq!(g.round(), -3.0); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn round(self) -> f32 { + unsafe { intrinsics::roundf32(self) } + } + + /// Returns the integer part of a number. + /// + /// ``` + /// let f = 3.3_f32; + /// let g = -3.7_f32; + /// + /// assert_eq!(f.trunc(), 3.0); + /// assert_eq!(g.trunc(), -3.0); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn trunc(self) -> f32 { + unsafe { intrinsics::truncf32(self) } + } + + /// Returns the fractional part of a number. + /// + /// ``` + /// use std::f32; + /// + /// let x = 3.5_f32; + /// let y = -3.5_f32; + /// let abs_difference_x = (x.fract() - 0.5).abs(); + /// let abs_difference_y = (y.fract() - (-0.5)).abs(); + /// + /// assert!(abs_difference_x <= f32::EPSILON); + /// assert!(abs_difference_y <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn fract(self) -> f32 { self - self.trunc() } + + /// Computes the absolute value of `self`. Returns `NAN` if the + /// number is `NAN`. + /// + /// ``` + /// use std::f32; + /// + /// let x = 3.5_f32; + /// let y = -3.5_f32; + /// + /// let abs_difference_x = (x.abs() - x).abs(); + /// let abs_difference_y = (y.abs() - (-y)).abs(); + /// + /// assert!(abs_difference_x <= f32::EPSILON); + /// assert!(abs_difference_y <= f32::EPSILON); + /// + /// assert!(f32::NAN.abs().is_nan()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn abs(self) -> f32 { num::Float::abs(self) } + + /// Returns a number that represents the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - `NAN` if the number is `NAN` + /// + /// ``` + /// use std::f32; + /// + /// let f = 3.5_f32; + /// + /// assert_eq!(f.signum(), 1.0); + /// assert_eq!(f32::NEG_INFINITY.signum(), -1.0); + /// + /// assert!(f32::NAN.signum().is_nan()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn signum(self) -> f32 { num::Float::signum(self) } + + /// Returns `true` if `self`'s sign bit is positive, including + /// `+0.0` and `INFINITY`. + /// + /// ``` + /// use std::f32; + /// + /// let nan = f32::NAN; + /// let f = 7.0_f32; + /// let g = -7.0_f32; + /// + /// assert!(f.is_sign_positive()); + /// assert!(!g.is_sign_positive()); + /// // 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) } + + /// Returns `true` if `self`'s sign is negative, including `-0.0` + /// and `NEG_INFINITY`. + /// + /// ``` + /// use std::f32; + /// + /// let nan = f32::NAN; + /// let f = 7.0f32; + /// let g = -7.0f32; + /// + /// assert!(!f.is_sign_negative()); + /// assert!(g.is_sign_negative()); + /// // 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) } + + /// Fused multiply-add. Computes `(self * a) + b` with only one rounding + /// error. This produces a more accurate result with better performance than + /// a separate multiplication operation followed by an add. + /// + /// ``` + /// use std::f32; + /// + /// let m = 10.0_f32; + /// let x = 4.0_f32; + /// let b = 60.0_f32; + /// + /// // 100.0 + /// let abs_difference = (m.mul_add(x, b) - (m*x + b)).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn mul_add(self, a: f32, b: f32) -> f32 { + unsafe { intrinsics::fmaf32(self, a, b) } + } + + /// Takes the reciprocal (inverse) of a number, `1/x`. + /// + /// ``` + /// use std::f32; + /// + /// let x = 2.0_f32; + /// let abs_difference = (x.recip() - (1.0/x)).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn recip(self) -> f32 { num::Float::recip(self) } + + /// Raises a number to an integer power. + /// + /// Using this function is generally faster than using `powf` + /// + /// ``` + /// use std::f32; + /// + /// let x = 2.0_f32; + /// let abs_difference = (x.powi(2) - x*x).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn powi(self, n: i32) -> f32 { num::Float::powi(self, n) } + + /// Raises a number to a floating point power. + /// + /// ``` + /// use std::f32; + /// + /// let x = 2.0_f32; + /// let abs_difference = (x.powf(2.0) - x*x).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn powf(self, n: f32) -> f32 { + // see notes above in `floor` + #[cfg(target_env = "msvc")] + return (self as f64).powf(n as f64) as f32; + #[cfg(not(target_env = "msvc"))] + return unsafe { intrinsics::powf32(self, n) }; + } + + /// Takes the square root of a number. + /// + /// Returns NaN if `self` is a negative number. + /// + /// ``` + /// use std::f32; + /// + /// let positive = 4.0_f32; + /// let negative = -4.0_f32; + /// + /// let abs_difference = (positive.sqrt() - 2.0).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// assert!(negative.sqrt().is_nan()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn sqrt(self) -> f32 { + if self < 0.0 { + NAN + } else { + unsafe { intrinsics::sqrtf32(self) } + } + } + + /// Returns `e^(self)`, (the exponential function). + /// + /// ``` + /// use std::f32; + /// + /// let one = 1.0f32; + /// // e^1 + /// let e = one.exp(); + /// + /// // ln(e) - 1 == 0 + /// let abs_difference = (e.ln() - 1.0).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn exp(self) -> f32 { + // see notes above in `floor` + #[cfg(target_env = "msvc")] + return (self as f64).exp() as f32; + #[cfg(not(target_env = "msvc"))] + return unsafe { intrinsics::expf32(self) }; + } + + /// Returns `2^(self)`. + /// + /// ``` + /// use std::f32; + /// + /// let f = 2.0f32; + /// + /// // 2^2 - 4 == 0 + /// let abs_difference = (f.exp2() - 4.0).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn exp2(self) -> f32 { + unsafe { intrinsics::exp2f32(self) } + } + + /// Returns the natural logarithm of the number. + /// + /// ``` + /// use std::f32; + /// + /// let one = 1.0f32; + /// // e^1 + /// let e = one.exp(); + /// + /// // ln(e) - 1 == 0 + /// let abs_difference = (e.ln() - 1.0).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn ln(self) -> f32 { + // see notes above in `floor` + #[cfg(target_env = "msvc")] + return (self as f64).ln() as f32; + #[cfg(not(target_env = "msvc"))] + return unsafe { intrinsics::logf32(self) }; + } + + /// Returns the logarithm of the number with respect to an arbitrary base. + /// + /// ``` + /// use std::f32; + /// + /// let ten = 10.0f32; + /// let two = 2.0f32; + /// + /// // log10(10) - 1 == 0 + /// let abs_difference_10 = (ten.log(10.0) - 1.0).abs(); + /// + /// // log2(2) - 1 == 0 + /// let abs_difference_2 = (two.log(2.0) - 1.0).abs(); + /// + /// 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() } + + /// Returns the base 2 logarithm of the number. + /// + /// ``` + /// use std::f32; + /// + /// let two = 2.0f32; + /// + /// // log2(2) - 1 == 0 + /// let abs_difference = (two.log2() - 1.0).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn log2(self) -> f32 { + #[cfg(target_os = "android")] + return ::sys::android::log2f32(self); + #[cfg(not(target_os = "android"))] + return unsafe { intrinsics::log2f32(self) }; + } + + /// Returns the base 10 logarithm of the number. + /// + /// ``` + /// use std::f32; + /// + /// let ten = 10.0f32; + /// + /// // log10(10) - 1 == 0 + /// let abs_difference = (ten.log10() - 1.0).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn log10(self) -> f32 { + // see notes above in `floor` + #[cfg(target_env = "msvc")] + return (self as f64).log10() as f32; + #[cfg(not(target_env = "msvc"))] + return unsafe { intrinsics::log10f32(self) }; + } + + /// Converts radians to degrees. + /// + /// ``` + /// use std::f32::{self, consts}; + /// + /// let angle = consts::PI; + /// + /// let abs_difference = (angle.to_degrees() - 180.0).abs(); + /// + /// 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) } + + /// Converts degrees to radians. + /// + /// ``` + /// use std::f32::{self, consts}; + /// + /// let angle = 180.0f32; + /// + /// let abs_difference = (angle.to_radians() - consts::PI).abs(); + /// + /// 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) } + + /// Constructs a floating point number of `x*2^exp`. + /// + /// ``` + /// #![feature(float_extras)] + /// + /// use std::f32; + /// // 3*2^2 - 12 == 0 + /// let abs_difference = (f32::ldexp(3.0, 2) - 12.0).abs(); + /// + /// 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) } + } + + /// Breaks the number into a normalized fraction and a base-2 exponent, + /// satisfying: + /// + /// * `self = x * 2^exp` + /// * `0.5 <= abs(x) < 1.0` + /// + /// ``` + /// #![feature(float_extras)] + /// + /// use std::f32; + /// + /// let x = 4.0f32; + /// + /// // (1/2)*2^3 -> 1 * 8/2 -> 4.0 + /// let f = x.frexp(); + /// let abs_difference_0 = (f.0 - 0.5).abs(); + /// let abs_difference_1 = (f.1 as f32 - 3.0).abs(); + /// + /// 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 { + let mut exp = 0; + let x = cmath::frexpf(self, &mut exp); + (x, exp as isize) + } + } + + /// Returns the next representable floating-point value in the direction of + /// `other`. + /// + /// ``` + /// #![feature(float_extras)] + /// + /// use std::f32; + /// + /// let x = 1.0f32; + /// + /// let abs_diff = (x.next_after(2.0) - 1.00000011920928955078125_f32).abs(); + /// + /// 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) } + } + + /// Returns the maximum of the two numbers. + /// + /// ``` + /// let x = 1.0f32; + /// let y = 2.0f32; + /// + /// assert_eq!(x.max(y), y); + /// ``` + /// + /// 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) } + } + + /// Returns the minimum of the two numbers. + /// + /// ``` + /// let x = 1.0f32; + /// let y = 2.0f32; + /// + /// assert_eq!(x.min(y), x); + /// ``` + /// + /// 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) } + } + + /// The positive difference of two numbers. + /// + /// * If `self <= other`: `0:0` + /// * Else: `self - other` + /// + /// ``` + /// use std::f32; + /// + /// let x = 3.0f32; + /// let y = -3.0f32; + /// + /// let abs_difference_x = (x.abs_sub(1.0) - 2.0).abs(); + /// let abs_difference_y = (y.abs_sub(1.0) - 0.0).abs(); + /// + /// assert!(abs_difference_x <= f32::EPSILON); + /// assert!(abs_difference_y <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[rustc_deprecated(since = "1.10.0", + reason = "you probably meant `(self - other).abs()`: \ + this operation is `(self - other).max(0.0)` (also \ + known as `fdimf` in C). If you truly need the positive \ + difference, consider using that expression or the C function \ + `fdimf`, depending on how you wish to handle NaN (please consider \ + filing an issue describing your use-case too).")] + pub fn abs_sub(self, other: f32) -> f32 { + unsafe { cmath::fdimf(self, other) } + } + + /// Takes the cubic root of a number. + /// + /// ``` + /// use std::f32; + /// + /// let x = 8.0f32; + /// + /// // x^(1/3) - 2 == 0 + /// let abs_difference = (x.cbrt() - 2.0).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn cbrt(self) -> f32 { + unsafe { cmath::cbrtf(self) } + } + + /// Calculates the length of the hypotenuse of a right-angle triangle given + /// legs of length `x` and `y`. + /// + /// ``` + /// use std::f32; + /// + /// let x = 2.0f32; + /// let y = 3.0f32; + /// + /// // sqrt(x^2 + y^2) + /// let abs_difference = (x.hypot(y) - (x.powi(2) + y.powi(2)).sqrt()).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn hypot(self, other: f32) -> f32 { + unsafe { cmath::hypotf(self, other) } + } + + /// Computes the sine of a number (in radians). + /// + /// ``` + /// use std::f32; + /// + /// let x = f32::consts::PI/2.0; + /// + /// let abs_difference = (x.sin() - 1.0).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn sin(self) -> f32 { + // see notes in `core::f32::Float::floor` + #[cfg(target_env = "msvc")] + return (self as f64).sin() as f32; + #[cfg(not(target_env = "msvc"))] + return unsafe { intrinsics::sinf32(self) }; + } + + /// Computes the cosine of a number (in radians). + /// + /// ``` + /// use std::f32; + /// + /// let x = 2.0*f32::consts::PI; + /// + /// let abs_difference = (x.cos() - 1.0).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn cos(self) -> f32 { + // see notes in `core::f32::Float::floor` + #[cfg(target_env = "msvc")] + return (self as f64).cos() as f32; + #[cfg(not(target_env = "msvc"))] + return unsafe { intrinsics::cosf32(self) }; + } + + /// Computes the tangent of a number (in radians). + /// + /// ``` + /// use std::f32; + /// + /// let x = f32::consts::PI / 4.0; + /// let abs_difference = (x.tan() - 1.0).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn tan(self) -> f32 { + unsafe { cmath::tanf(self) } + } + + /// Computes the arcsine of a number. Return value is in radians in + /// the range [-pi/2, pi/2] or NaN if the number is outside the range + /// [-1, 1]. + /// + /// ``` + /// use std::f32; + /// + /// let f = f32::consts::PI / 2.0; + /// + /// // asin(sin(pi/2)) + /// let abs_difference = (f.sin().asin() - f32::consts::PI / 2.0).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn asin(self) -> f32 { + unsafe { cmath::asinf(self) } + } + + /// Computes the arccosine of a number. Return value is in radians in + /// the range [0, pi] or NaN if the number is outside the range + /// [-1, 1]. + /// + /// ``` + /// use std::f32; + /// + /// let f = f32::consts::PI / 4.0; + /// + /// // acos(cos(pi/4)) + /// let abs_difference = (f.cos().acos() - f32::consts::PI / 4.0).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn acos(self) -> f32 { + unsafe { cmath::acosf(self) } + } + + /// Computes the arctangent of a number. Return value is in radians in the + /// range [-pi/2, pi/2]; + /// + /// ``` + /// use std::f32; + /// + /// let f = 1.0f32; + /// + /// // atan(tan(1)) + /// let abs_difference = (f.tan().atan() - 1.0).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn atan(self) -> f32 { + unsafe { cmath::atanf(self) } + } + + /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`). + /// + /// * `x = 0`, `y = 0`: `0` + /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]` + /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` + /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` + /// + /// ``` + /// use std::f32; + /// + /// let pi = f32::consts::PI; + /// // All angles from horizontal right (+x) + /// // 45 deg counter-clockwise + /// let x1 = 3.0f32; + /// let y1 = -3.0f32; + /// + /// // 135 deg clockwise + /// let x2 = -3.0f32; + /// let y2 = 3.0f32; + /// + /// let abs_difference_1 = (y1.atan2(x1) - (-pi/4.0)).abs(); + /// let abs_difference_2 = (y2.atan2(x2) - 3.0*pi/4.0).abs(); + /// + /// assert!(abs_difference_1 <= f32::EPSILON); + /// assert!(abs_difference_2 <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn atan2(self, other: f32) -> f32 { + unsafe { cmath::atan2f(self, other) } + } + + /// Simultaneously computes the sine and cosine of the number, `x`. Returns + /// `(sin(x), cos(x))`. + /// + /// ``` + /// use std::f32; + /// + /// let x = f32::consts::PI/4.0; + /// let f = x.sin_cos(); + /// + /// let abs_difference_0 = (f.0 - x.sin()).abs(); + /// let abs_difference_1 = (f.1 - x.cos()).abs(); + /// + /// assert!(abs_difference_0 <= f32::EPSILON); + /// assert!(abs_difference_1 <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn sin_cos(self) -> (f32, f32) { + (self.sin(), self.cos()) + } + + /// Returns `e^(self) - 1` in a way that is accurate even if the + /// number is close to zero. + /// + /// ``` + /// use std::f32; + /// + /// let x = 6.0f32; + /// + /// // e^(ln(6)) - 1 + /// let abs_difference = (x.ln().exp_m1() - 5.0).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn exp_m1(self) -> f32 { + unsafe { cmath::expm1f(self) } + } + + /// Returns `ln(1+n)` (natural logarithm) more accurately than if + /// the operations were performed separately. + /// + /// ``` + /// use std::f32; + /// + /// let x = f32::consts::E - 1.0; + /// + /// // ln(1 + (e - 1)) == ln(e) == 1 + /// let abs_difference = (x.ln_1p() - 1.0).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn ln_1p(self) -> f32 { + unsafe { cmath::log1pf(self) } + } + + /// Hyperbolic sine function. + /// + /// ``` + /// use std::f32; + /// + /// let e = f32::consts::E; + /// let x = 1.0f32; + /// + /// let f = x.sinh(); + /// // Solving sinh() at 1 gives `(e^2-1)/(2e)` + /// let g = (e*e - 1.0)/(2.0*e); + /// let abs_difference = (f - g).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn sinh(self) -> f32 { + unsafe { cmath::sinhf(self) } + } + + /// Hyperbolic cosine function. + /// + /// ``` + /// use std::f32; + /// + /// let e = f32::consts::E; + /// let x = 1.0f32; + /// let f = x.cosh(); + /// // Solving cosh() at 1 gives this result + /// let g = (e*e + 1.0)/(2.0*e); + /// let abs_difference = (f - g).abs(); + /// + /// // Same result + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn cosh(self) -> f32 { + unsafe { cmath::coshf(self) } + } + + /// Hyperbolic tangent function. + /// + /// ``` + /// use std::f32; + /// + /// let e = f32::consts::E; + /// let x = 1.0f32; + /// + /// let f = x.tanh(); + /// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))` + /// let g = (1.0 - e.powi(-2))/(1.0 + e.powi(-2)); + /// let abs_difference = (f - g).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn tanh(self) -> f32 { + unsafe { cmath::tanhf(self) } + } + + /// Inverse hyperbolic sine function. + /// + /// ``` + /// use std::f32; + /// + /// let x = 1.0f32; + /// let f = x.sinh().asinh(); + /// + /// let abs_difference = (f - x).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn asinh(self) -> f32 { + if self == NEG_INFINITY { + NEG_INFINITY + } else { + (self + ((self * self) + 1.0).sqrt()).ln() + } + } + + /// Inverse hyperbolic cosine function. + /// + /// ``` + /// use std::f32; + /// + /// let x = 1.0f32; + /// let f = x.cosh().acosh(); + /// + /// let abs_difference = (f - x).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn acosh(self) -> f32 { + match self { + x if x < 1.0 => ::f32::NAN, + x => (x + ((x * x) - 1.0).sqrt()).ln(), + } + } + + /// Inverse hyperbolic tangent function. + /// + /// ``` + /// use std::f32; + /// + /// let e = f32::consts::E; + /// let f = e.tanh().atanh(); + /// + /// let abs_difference = (f - e).abs(); + /// + /// assert!(abs_difference <= 1e-5); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn atanh(self) -> f32 { + 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() + } +} + +#[cfg(test)] +mod tests { + use f32; + use f32::*; + use num::*; + use num::FpCategory as Fp; + + #[test] + fn test_num_f32() { + test_num(10f32, 2f32); + } + + #[test] + fn test_min_nan() { + assert_eq!(NAN.min(2.0), 2.0); + assert_eq!(2.0f32.min(NAN), 2.0); + } + + #[test] + fn test_max_nan() { + assert_eq!(NAN.max(2.0), 2.0); + assert_eq!(2.0f32.max(NAN), 2.0); + } + + #[test] + fn test_nan() { + let nan: f32 = f32::NAN; + assert!(nan.is_nan()); + assert!(!nan.is_infinite()); + assert!(!nan.is_finite()); + assert!(!nan.is_normal()); + assert!(!nan.is_sign_positive()); + assert!(!nan.is_sign_negative()); + assert_eq!(Fp::Nan, nan.classify()); + } + + #[test] + fn test_infinity() { + let inf: f32 = f32::INFINITY; + assert!(inf.is_infinite()); + assert!(!inf.is_finite()); + assert!(inf.is_sign_positive()); + assert!(!inf.is_sign_negative()); + assert!(!inf.is_nan()); + assert!(!inf.is_normal()); + assert_eq!(Fp::Infinite, inf.classify()); + } + + #[test] + fn test_neg_infinity() { + let neg_inf: f32 = f32::NEG_INFINITY; + assert!(neg_inf.is_infinite()); + assert!(!neg_inf.is_finite()); + assert!(!neg_inf.is_sign_positive()); + assert!(neg_inf.is_sign_negative()); + assert!(!neg_inf.is_nan()); + assert!(!neg_inf.is_normal()); + assert_eq!(Fp::Infinite, neg_inf.classify()); + } + + #[test] + fn test_zero() { + let zero: f32 = 0.0f32; + assert_eq!(0.0, zero); + assert!(!zero.is_infinite()); + assert!(zero.is_finite()); + assert!(zero.is_sign_positive()); + assert!(!zero.is_sign_negative()); + assert!(!zero.is_nan()); + assert!(!zero.is_normal()); + assert_eq!(Fp::Zero, zero.classify()); + } + + #[test] + fn test_neg_zero() { + let neg_zero: f32 = -0.0; + assert_eq!(0.0, neg_zero); + assert!(!neg_zero.is_infinite()); + assert!(neg_zero.is_finite()); + assert!(!neg_zero.is_sign_positive()); + assert!(neg_zero.is_sign_negative()); + assert!(!neg_zero.is_nan()); + assert!(!neg_zero.is_normal()); + assert_eq!(Fp::Zero, neg_zero.classify()); + } + + #[test] + fn test_one() { + let one: f32 = 1.0f32; + assert_eq!(1.0, one); + assert!(!one.is_infinite()); + assert!(one.is_finite()); + assert!(one.is_sign_positive()); + assert!(!one.is_sign_negative()); + assert!(!one.is_nan()); + assert!(one.is_normal()); + assert_eq!(Fp::Normal, one.classify()); + } + + #[test] + fn test_is_nan() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert!(nan.is_nan()); + assert!(!0.0f32.is_nan()); + assert!(!5.3f32.is_nan()); + assert!(!(-10.732f32).is_nan()); + assert!(!inf.is_nan()); + assert!(!neg_inf.is_nan()); + } + + #[test] + fn test_is_infinite() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert!(!nan.is_infinite()); + assert!(inf.is_infinite()); + assert!(neg_inf.is_infinite()); + assert!(!0.0f32.is_infinite()); + assert!(!42.8f32.is_infinite()); + assert!(!(-109.2f32).is_infinite()); + } + + #[test] + fn test_is_finite() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert!(!nan.is_finite()); + assert!(!inf.is_finite()); + assert!(!neg_inf.is_finite()); + assert!(0.0f32.is_finite()); + assert!(42.8f32.is_finite()); + assert!((-109.2f32).is_finite()); + } + + #[test] + fn test_is_normal() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let zero: f32 = 0.0f32; + let neg_zero: f32 = -0.0; + assert!(!nan.is_normal()); + assert!(!inf.is_normal()); + assert!(!neg_inf.is_normal()); + assert!(!zero.is_normal()); + assert!(!neg_zero.is_normal()); + assert!(1f32.is_normal()); + assert!(1e-37f32.is_normal()); + assert!(!1e-38f32.is_normal()); + } + + #[test] + fn test_classify() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let zero: f32 = 0.0f32; + let neg_zero: f32 = -0.0; + assert_eq!(nan.classify(), Fp::Nan); + assert_eq!(inf.classify(), Fp::Infinite); + assert_eq!(neg_inf.classify(), Fp::Infinite); + assert_eq!(zero.classify(), Fp::Zero); + assert_eq!(neg_zero.classify(), Fp::Zero); + assert_eq!(1f32.classify(), Fp::Normal); + assert_eq!(1e-37f32.classify(), Fp::Normal); + assert_eq!(1e-38f32.classify(), Fp::Subnormal); + } + + #[test] + #[allow(deprecated)] + fn test_integer_decode() { + assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1)); + assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1)); + assert_eq!(2f32.powf(100.0).integer_decode(), (8388608, 77, 1)); + assert_eq!(0f32.integer_decode(), (0, -150, 1)); + assert_eq!((-0f32).integer_decode(), (0, -150, -1)); + assert_eq!(INFINITY.integer_decode(), (8388608, 105, 1)); + assert_eq!(NEG_INFINITY.integer_decode(), (8388608, 105, -1)); + + // Ignore the "sign" (quiet / signalling flag) of NAN. + // It can vary between runtime operations and LLVM folding. + let (nan_m, nan_e, _nan_s) = NAN.integer_decode(); + assert_eq!((nan_m, nan_e), (12582912, 105)); + } + + #[test] + fn test_floor() { + assert_approx_eq!(1.0f32.floor(), 1.0f32); + assert_approx_eq!(1.3f32.floor(), 1.0f32); + assert_approx_eq!(1.5f32.floor(), 1.0f32); + assert_approx_eq!(1.7f32.floor(), 1.0f32); + assert_approx_eq!(0.0f32.floor(), 0.0f32); + assert_approx_eq!((-0.0f32).floor(), -0.0f32); + assert_approx_eq!((-1.0f32).floor(), -1.0f32); + assert_approx_eq!((-1.3f32).floor(), -2.0f32); + assert_approx_eq!((-1.5f32).floor(), -2.0f32); + assert_approx_eq!((-1.7f32).floor(), -2.0f32); + } + + #[test] + fn test_ceil() { + assert_approx_eq!(1.0f32.ceil(), 1.0f32); + assert_approx_eq!(1.3f32.ceil(), 2.0f32); + assert_approx_eq!(1.5f32.ceil(), 2.0f32); + assert_approx_eq!(1.7f32.ceil(), 2.0f32); + assert_approx_eq!(0.0f32.ceil(), 0.0f32); + assert_approx_eq!((-0.0f32).ceil(), -0.0f32); + assert_approx_eq!((-1.0f32).ceil(), -1.0f32); + assert_approx_eq!((-1.3f32).ceil(), -1.0f32); + assert_approx_eq!((-1.5f32).ceil(), -1.0f32); + assert_approx_eq!((-1.7f32).ceil(), -1.0f32); + } + + #[test] + fn test_round() { + assert_approx_eq!(1.0f32.round(), 1.0f32); + assert_approx_eq!(1.3f32.round(), 1.0f32); + assert_approx_eq!(1.5f32.round(), 2.0f32); + assert_approx_eq!(1.7f32.round(), 2.0f32); + assert_approx_eq!(0.0f32.round(), 0.0f32); + assert_approx_eq!((-0.0f32).round(), -0.0f32); + assert_approx_eq!((-1.0f32).round(), -1.0f32); + assert_approx_eq!((-1.3f32).round(), -1.0f32); + assert_approx_eq!((-1.5f32).round(), -2.0f32); + assert_approx_eq!((-1.7f32).round(), -2.0f32); + } + + #[test] + fn test_trunc() { + assert_approx_eq!(1.0f32.trunc(), 1.0f32); + assert_approx_eq!(1.3f32.trunc(), 1.0f32); + assert_approx_eq!(1.5f32.trunc(), 1.0f32); + assert_approx_eq!(1.7f32.trunc(), 1.0f32); + assert_approx_eq!(0.0f32.trunc(), 0.0f32); + assert_approx_eq!((-0.0f32).trunc(), -0.0f32); + assert_approx_eq!((-1.0f32).trunc(), -1.0f32); + assert_approx_eq!((-1.3f32).trunc(), -1.0f32); + assert_approx_eq!((-1.5f32).trunc(), -1.0f32); + assert_approx_eq!((-1.7f32).trunc(), -1.0f32); + } + + #[test] + fn test_fract() { + assert_approx_eq!(1.0f32.fract(), 0.0f32); + assert_approx_eq!(1.3f32.fract(), 0.3f32); + assert_approx_eq!(1.5f32.fract(), 0.5f32); + assert_approx_eq!(1.7f32.fract(), 0.7f32); + assert_approx_eq!(0.0f32.fract(), 0.0f32); + assert_approx_eq!((-0.0f32).fract(), -0.0f32); + assert_approx_eq!((-1.0f32).fract(), -0.0f32); + assert_approx_eq!((-1.3f32).fract(), -0.3f32); + assert_approx_eq!((-1.5f32).fract(), -0.5f32); + assert_approx_eq!((-1.7f32).fract(), -0.7f32); + } + + #[test] + fn test_abs() { + assert_eq!(INFINITY.abs(), INFINITY); + assert_eq!(1f32.abs(), 1f32); + assert_eq!(0f32.abs(), 0f32); + assert_eq!((-0f32).abs(), 0f32); + assert_eq!((-1f32).abs(), 1f32); + assert_eq!(NEG_INFINITY.abs(), INFINITY); + assert_eq!((1f32/NEG_INFINITY).abs(), 0f32); + assert!(NAN.abs().is_nan()); + } + + #[test] + fn test_signum() { + assert_eq!(INFINITY.signum(), 1f32); + assert_eq!(1f32.signum(), 1f32); + assert_eq!(0f32.signum(), 1f32); + assert_eq!((-0f32).signum(), -1f32); + assert_eq!((-1f32).signum(), -1f32); + assert_eq!(NEG_INFINITY.signum(), -1f32); + assert_eq!((1f32/NEG_INFINITY).signum(), -1f32); + assert!(NAN.signum().is_nan()); + } + + #[test] + fn test_is_sign_positive() { + assert!(INFINITY.is_sign_positive()); + assert!(1f32.is_sign_positive()); + assert!(0f32.is_sign_positive()); + assert!(!(-0f32).is_sign_positive()); + assert!(!(-1f32).is_sign_positive()); + assert!(!NEG_INFINITY.is_sign_positive()); + assert!(!(1f32/NEG_INFINITY).is_sign_positive()); + assert!(!NAN.is_sign_positive()); + } + + #[test] + fn test_is_sign_negative() { + assert!(!INFINITY.is_sign_negative()); + assert!(!1f32.is_sign_negative()); + assert!(!0f32.is_sign_negative()); + assert!((-0f32).is_sign_negative()); + assert!((-1f32).is_sign_negative()); + assert!(NEG_INFINITY.is_sign_negative()); + assert!((1f32/NEG_INFINITY).is_sign_negative()); + assert!(!NAN.is_sign_negative()); + } + + #[test] + fn test_mul_add() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_approx_eq!(12.3f32.mul_add(4.5, 6.7), 62.05); + assert_approx_eq!((-12.3f32).mul_add(-4.5, -6.7), 48.65); + assert_approx_eq!(0.0f32.mul_add(8.9, 1.2), 1.2); + assert_approx_eq!(3.4f32.mul_add(-0.0, 5.6), 5.6); + assert!(nan.mul_add(7.8, 9.0).is_nan()); + assert_eq!(inf.mul_add(7.8, 9.0), inf); + assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf); + assert_eq!(8.9f32.mul_add(inf, 3.2), inf); + assert_eq!((-3.2f32).mul_add(2.4, neg_inf), neg_inf); + } + + #[test] + fn test_recip() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(1.0f32.recip(), 1.0); + assert_eq!(2.0f32.recip(), 0.5); + assert_eq!((-0.4f32).recip(), -2.5); + assert_eq!(0.0f32.recip(), inf); + assert!(nan.recip().is_nan()); + assert_eq!(inf.recip(), 0.0); + assert_eq!(neg_inf.recip(), 0.0); + } + + #[test] + fn test_powi() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(1.0f32.powi(1), 1.0); + assert_approx_eq!((-3.1f32).powi(2), 9.61); + assert_approx_eq!(5.9f32.powi(-2), 0.028727); + assert_eq!(8.3f32.powi(0), 1.0); + assert!(nan.powi(2).is_nan()); + assert_eq!(inf.powi(3), inf); + assert_eq!(neg_inf.powi(2), inf); + } + + #[test] + fn test_powf() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(1.0f32.powf(1.0), 1.0); + assert_approx_eq!(3.4f32.powf(4.5), 246.408218); + assert_approx_eq!(2.7f32.powf(-3.2), 0.041652); + assert_approx_eq!((-3.1f32).powf(2.0), 9.61); + assert_approx_eq!(5.9f32.powf(-2.0), 0.028727); + assert_eq!(8.3f32.powf(0.0), 1.0); + assert!(nan.powf(2.0).is_nan()); + assert_eq!(inf.powf(2.0), inf); + assert_eq!(neg_inf.powf(3.0), neg_inf); + } + + #[test] + fn test_sqrt_domain() { + assert!(NAN.sqrt().is_nan()); + assert!(NEG_INFINITY.sqrt().is_nan()); + assert!((-1.0f32).sqrt().is_nan()); + assert_eq!((-0.0f32).sqrt(), -0.0); + assert_eq!(0.0f32.sqrt(), 0.0); + assert_eq!(1.0f32.sqrt(), 1.0); + assert_eq!(INFINITY.sqrt(), INFINITY); + } + + #[test] + fn test_exp() { + assert_eq!(1.0, 0.0f32.exp()); + assert_approx_eq!(2.718282, 1.0f32.exp()); + assert_approx_eq!(148.413162, 5.0f32.exp()); + + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let nan: f32 = f32::NAN; + assert_eq!(inf, inf.exp()); + assert_eq!(0.0, neg_inf.exp()); + assert!(nan.exp().is_nan()); + } + + #[test] + fn test_exp2() { + assert_eq!(32.0, 5.0f32.exp2()); + assert_eq!(1.0, 0.0f32.exp2()); + + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let nan: f32 = f32::NAN; + assert_eq!(inf, inf.exp2()); + assert_eq!(0.0, neg_inf.exp2()); + assert!(nan.exp2().is_nan()); + } + + #[test] + fn test_ln() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_approx_eq!(1.0f32.exp().ln(), 1.0); + assert!(nan.ln().is_nan()); + assert_eq!(inf.ln(), inf); + assert!(neg_inf.ln().is_nan()); + assert!((-2.3f32).ln().is_nan()); + assert_eq!((-0.0f32).ln(), neg_inf); + assert_eq!(0.0f32.ln(), neg_inf); + assert_approx_eq!(4.0f32.ln(), 1.386294); + } + + #[test] + fn test_log() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(10.0f32.log(10.0), 1.0); + assert_approx_eq!(2.3f32.log(3.5), 0.664858); + assert_eq!(1.0f32.exp().log(1.0f32.exp()), 1.0); + assert!(1.0f32.log(1.0).is_nan()); + assert!(1.0f32.log(-13.9).is_nan()); + assert!(nan.log(2.3).is_nan()); + assert_eq!(inf.log(10.0), inf); + assert!(neg_inf.log(8.8).is_nan()); + assert!((-2.3f32).log(0.1).is_nan()); + assert_eq!((-0.0f32).log(2.0), neg_inf); + assert_eq!(0.0f32.log(7.0), neg_inf); + } + + #[test] + fn test_log2() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_approx_eq!(10.0f32.log2(), 3.321928); + assert_approx_eq!(2.3f32.log2(), 1.201634); + assert_approx_eq!(1.0f32.exp().log2(), 1.442695); + assert!(nan.log2().is_nan()); + assert_eq!(inf.log2(), inf); + assert!(neg_inf.log2().is_nan()); + assert!((-2.3f32).log2().is_nan()); + assert_eq!((-0.0f32).log2(), neg_inf); + assert_eq!(0.0f32.log2(), neg_inf); + } + + #[test] + fn test_log10() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(10.0f32.log10(), 1.0); + assert_approx_eq!(2.3f32.log10(), 0.361728); + assert_approx_eq!(1.0f32.exp().log10(), 0.434294); + assert_eq!(1.0f32.log10(), 0.0); + assert!(nan.log10().is_nan()); + assert_eq!(inf.log10(), inf); + assert!(neg_inf.log10().is_nan()); + assert!((-2.3f32).log10().is_nan()); + assert_eq!((-0.0f32).log10(), neg_inf); + assert_eq!(0.0f32.log10(), neg_inf); + } + + #[test] + fn test_to_degrees() { + let pi: f32 = consts::PI; + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(0.0f32.to_degrees(), 0.0); + assert_approx_eq!((-5.8f32).to_degrees(), -332.315521); + assert_eq!(pi.to_degrees(), 180.0); + assert!(nan.to_degrees().is_nan()); + assert_eq!(inf.to_degrees(), inf); + assert_eq!(neg_inf.to_degrees(), neg_inf); + } + + #[test] + fn test_to_radians() { + let pi: f32 = consts::PI; + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(0.0f32.to_radians(), 0.0); + assert_approx_eq!(154.6f32.to_radians(), 2.698279); + assert_approx_eq!((-332.31f32).to_radians(), -5.799903); + assert_eq!(180.0f32.to_radians(), pi); + assert!(nan.to_radians().is_nan()); + assert_eq!(inf.to_radians(), inf); + assert_eq!(neg_inf.to_radians(), neg_inf); + } + + #[test] + #[allow(deprecated)] + fn test_ldexp() { + let f1 = 2.0f32.powi(-123); + let f2 = 2.0f32.powi(-111); + let f3 = 1.75 * 2.0f32.powi(-12); + assert_eq!(f32::ldexp(1f32, -123), f1); + assert_eq!(f32::ldexp(1f32, -111), f2); + assert_eq!(f32::ldexp(1.75f32, -12), f3); + + assert_eq!(f32::ldexp(0f32, -123), 0f32); + assert_eq!(f32::ldexp(-0f32, -123), -0f32); + + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let nan: f32 = f32::NAN; + assert_eq!(f32::ldexp(inf, -123), inf); + assert_eq!(f32::ldexp(neg_inf, -123), neg_inf); + assert!(f32::ldexp(nan, -123).is_nan()); + } + + #[test] + #[allow(deprecated)] + fn test_frexp() { + let f1 = 2.0f32.powi(-123); + let f2 = 2.0f32.powi(-111); + let f3 = 1.75 * 2.0f32.powi(-123); + let (x1, exp1) = f1.frexp(); + let (x2, exp2) = f2.frexp(); + let (x3, exp3) = f3.frexp(); + assert_eq!((x1, exp1), (0.5f32, -122)); + assert_eq!((x2, exp2), (0.5f32, -110)); + assert_eq!((x3, exp3), (0.875f32, -122)); + assert_eq!(f32::ldexp(x1, exp1), f1); + assert_eq!(f32::ldexp(x2, exp2), f2); + assert_eq!(f32::ldexp(x3, exp3), f3); + + assert_eq!(0f32.frexp(), (0f32, 0)); + assert_eq!((-0f32).frexp(), (-0f32, 0)); + } + + #[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() }) + } + + #[test] + fn test_asinh() { + assert_eq!(0.0f32.asinh(), 0.0f32); + assert_eq!((-0.0f32).asinh(), -0.0f32); + + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let nan: f32 = f32::NAN; + assert_eq!(inf.asinh(), inf); + assert_eq!(neg_inf.asinh(), neg_inf); + assert!(nan.asinh().is_nan()); + assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32); + assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32); + } + + #[test] + fn test_acosh() { + assert_eq!(1.0f32.acosh(), 0.0f32); + assert!(0.999f32.acosh().is_nan()); + + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let nan: f32 = f32::NAN; + assert_eq!(inf.acosh(), inf); + assert!(neg_inf.acosh().is_nan()); + assert!(nan.acosh().is_nan()); + assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32); + assert_approx_eq!(3.0f32.acosh(), 1.76274717403908605046521864995958461f32); + } + + #[test] + fn test_atanh() { + assert_eq!(0.0f32.atanh(), 0.0f32); + assert_eq!((-0.0f32).atanh(), -0.0f32); + + let inf32: f32 = f32::INFINITY; + let neg_inf32: f32 = f32::NEG_INFINITY; + assert_eq!(1.0f32.atanh(), inf32); + assert_eq!((-1.0f32).atanh(), neg_inf32); + + assert!(2f64.atanh().atanh().is_nan()); + assert!((-2f64).atanh().atanh().is_nan()); + + let inf64: f32 = f32::INFINITY; + let neg_inf64: f32 = f32::NEG_INFINITY; + let nan32: f32 = f32::NAN; + assert!(inf64.atanh().is_nan()); + assert!(neg_inf64.atanh().is_nan()); + assert!(nan32.atanh().is_nan()); + + assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32); + assert_approx_eq!((-0.5f32).atanh(), -0.54930614433405484569762261846126285f32); + } + + #[test] + fn test_real_consts() { + use super::consts; + + let pi: f32 = consts::PI; + let frac_pi_2: f32 = consts::FRAC_PI_2; + let frac_pi_3: f32 = consts::FRAC_PI_3; + let frac_pi_4: f32 = consts::FRAC_PI_4; + let frac_pi_6: f32 = consts::FRAC_PI_6; + let frac_pi_8: f32 = consts::FRAC_PI_8; + let frac_1_pi: f32 = consts::FRAC_1_PI; + let frac_2_pi: f32 = consts::FRAC_2_PI; + let frac_2_sqrtpi: f32 = consts::FRAC_2_SQRT_PI; + let sqrt2: f32 = consts::SQRT_2; + let frac_1_sqrt2: f32 = consts::FRAC_1_SQRT_2; + let e: f32 = consts::E; + let log2_e: f32 = consts::LOG2_E; + let log10_e: f32 = consts::LOG10_E; + let ln_2: f32 = consts::LN_2; + let ln_10: f32 = consts::LN_10; + + assert_approx_eq!(frac_pi_2, pi / 2f32); + assert_approx_eq!(frac_pi_3, pi / 3f32); + assert_approx_eq!(frac_pi_4, pi / 4f32); + assert_approx_eq!(frac_pi_6, pi / 6f32); + assert_approx_eq!(frac_pi_8, pi / 8f32); + assert_approx_eq!(frac_1_pi, 1f32 / pi); + assert_approx_eq!(frac_2_pi, 2f32 / pi); + assert_approx_eq!(frac_2_sqrtpi, 2f32 / pi.sqrt()); + assert_approx_eq!(sqrt2, 2f32.sqrt()); + assert_approx_eq!(frac_1_sqrt2, 1f32 / 2f32.sqrt()); + assert_approx_eq!(log2_e, e.log2()); + assert_approx_eq!(log10_e, e.log10()); + assert_approx_eq!(ln_2, 2f32.ln()); + assert_approx_eq!(ln_10, 10f32.ln()); + } +} diff --git a/ctr-std/src/f64.rs b/ctr-std/src/f64.rs new file mode 100644 index 0000000..67a1c30 --- /dev/null +++ b/ctr-std/src/f64.rs @@ -0,0 +1,1756 @@ +// 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. + +//! The 64-bit floating point type. +//! +//! *[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 intrinsics; +#[cfg(not(test))] +use libc::c_int; +#[cfg(not(test))] +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 libc::{c_double, c_int}; + + #[link_name = "m"] + extern { + pub fn acos(n: c_double) -> c_double; + pub fn asin(n: c_double) -> c_double; + pub fn atan(n: c_double) -> c_double; + pub fn atan2(a: c_double, b: c_double) -> c_double; + pub fn cbrt(n: c_double) -> c_double; + pub fn cosh(n: c_double) -> c_double; + pub fn erf(n: c_double) -> c_double; + pub fn erfc(n: c_double) -> c_double; + pub fn expm1(n: c_double) -> c_double; + pub fn fdim(a: c_double, b: c_double) -> c_double; + pub fn fmax(a: c_double, b: c_double) -> c_double; + pub fn fmin(a: c_double, b: c_double) -> c_double; + pub fn fmod(a: c_double, b: c_double) -> c_double; + pub fn frexp(n: c_double, value: &mut c_int) -> c_double; + pub fn ilogb(n: c_double) -> c_int; + pub fn ldexp(x: c_double, n: c_int) -> c_double; + pub fn logb(n: c_double) -> c_double; + pub fn log1p(n: c_double) -> c_double; + pub fn nextafter(x: c_double, y: c_double) -> c_double; + pub fn modf(n: c_double, iptr: &mut c_double) -> c_double; + pub fn sinh(n: c_double) -> c_double; + pub fn tan(n: c_double) -> c_double; + pub fn tanh(n: c_double) -> c_double; + pub fn tgamma(n: c_double) -> c_double; + + // These are commonly only available for doubles + + pub fn j0(n: c_double) -> c_double; + pub fn j1(n: c_double) -> c_double; + pub fn jn(i: c_int, n: c_double) -> c_double; + + pub fn y0(n: c_double) -> c_double; + pub fn y1(n: c_double) -> c_double; + pub fn yn(i: c_int, n: c_double) -> c_double; + + #[cfg_attr(all(windows, target_env = "msvc"), link_name = "__lgamma_r")] + pub fn lgamma_r(n: c_double, sign: &mut c_int) -> c_double; + + #[cfg_attr(all(windows, target_env = "msvc"), link_name = "_hypot")] + pub fn hypot(x: c_double, y: c_double) -> c_double; + } +} + +#[cfg(not(test))] +#[lang = "f64"] +impl f64 { + /// Returns `true` if this value is `NaN` and false otherwise. + /// + /// ``` + /// use std::f64; + /// + /// let nan = f64::NAN; + /// let f = 7.0_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) } + + /// Returns `true` if this value is positive infinity or negative infinity and + /// false otherwise. + /// + /// ``` + /// use std::f64; + /// + /// let f = 7.0f64; + /// let inf = f64::INFINITY; + /// let neg_inf = f64::NEG_INFINITY; + /// let nan = f64::NAN; + /// + /// assert!(!f.is_infinite()); + /// assert!(!nan.is_infinite()); + /// + /// 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) } + + /// Returns `true` if this number is neither infinite nor `NaN`. + /// + /// ``` + /// use std::f64; + /// + /// let f = 7.0f64; + /// let inf: f64 = f64::INFINITY; + /// let neg_inf: f64 = f64::NEG_INFINITY; + /// let nan: f64 = f64::NAN; + /// + /// assert!(f.is_finite()); + /// + /// assert!(!nan.is_finite()); + /// 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) } + + /// Returns `true` if the number is neither zero, infinite, + /// [subnormal][subnormal], or `NaN`. + /// + /// ``` + /// use std::f64; + /// + /// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308f64 + /// let max = f64::MAX; + /// let lower_than_min = 1.0e-308_f64; + /// let zero = 0.0f64; + /// + /// assert!(min.is_normal()); + /// assert!(max.is_normal()); + /// + /// assert!(!zero.is_normal()); + /// assert!(!f64::NAN.is_normal()); + /// assert!(!f64::INFINITY.is_normal()); + /// // Values between `0` and `min` are Subnormal. + /// 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) } + + /// 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 + /// predicate instead. + /// + /// ``` + /// use std::num::FpCategory; + /// use std::f64; + /// + /// let num = 12.4_f64; + /// let inf = f64::INFINITY; + /// + /// 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) } + + /// Returns the mantissa, base 2 exponent, and sign as integers, respectively. + /// The original number can be recovered by `sign * mantissa * 2 ^ exponent`. + /// The floating point encoding is documented in the [Reference][floating-point]. + /// + /// ``` + /// #![feature(float_extras)] + /// + /// let num = 2.0f64; + /// + /// // (8388608, -22, 1) + /// let (mantissa, exponent, sign) = num.integer_decode(); + /// let sign_f = sign as f64; + /// let mantissa_f = mantissa as f64; + /// let exponent_f = num.powf(exponent as f64); + /// + /// // 1 * 8388608 * 2^(-22) == 2 + /// let abs_difference = (sign_f * mantissa_f * exponent_f - num).abs(); + /// + /// 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) } + + /// Returns the largest integer less than or equal to a number. + /// + /// ``` + /// let f = 3.99_f64; + /// let g = 3.0_f64; + /// + /// assert_eq!(f.floor(), 3.0); + /// assert_eq!(g.floor(), 3.0); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn floor(self) -> f64 { + unsafe { intrinsics::floorf64(self) } + } + + /// Returns the smallest integer greater than or equal to a number. + /// + /// ``` + /// let f = 3.01_f64; + /// let g = 4.0_f64; + /// + /// assert_eq!(f.ceil(), 4.0); + /// assert_eq!(g.ceil(), 4.0); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn ceil(self) -> f64 { + unsafe { intrinsics::ceilf64(self) } + } + + /// Returns the nearest integer to a number. Round half-way cases away from + /// `0.0`. + /// + /// ``` + /// let f = 3.3_f64; + /// let g = -3.3_f64; + /// + /// assert_eq!(f.round(), 3.0); + /// assert_eq!(g.round(), -3.0); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn round(self) -> f64 { + unsafe { intrinsics::roundf64(self) } + } + + /// Returns the integer part of a number. + /// + /// ``` + /// let f = 3.3_f64; + /// let g = -3.7_f64; + /// + /// assert_eq!(f.trunc(), 3.0); + /// assert_eq!(g.trunc(), -3.0); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn trunc(self) -> f64 { + unsafe { intrinsics::truncf64(self) } + } + + /// Returns the fractional part of a number. + /// + /// ``` + /// let x = 3.5_f64; + /// let y = -3.5_f64; + /// let abs_difference_x = (x.fract() - 0.5).abs(); + /// let abs_difference_y = (y.fract() - (-0.5)).abs(); + /// + /// assert!(abs_difference_x < 1e-10); + /// assert!(abs_difference_y < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn fract(self) -> f64 { self - self.trunc() } + + /// Computes the absolute value of `self`. Returns `NAN` if the + /// number is `NAN`. + /// + /// ``` + /// use std::f64; + /// + /// let x = 3.5_f64; + /// let y = -3.5_f64; + /// + /// let abs_difference_x = (x.abs() - x).abs(); + /// let abs_difference_y = (y.abs() - (-y)).abs(); + /// + /// assert!(abs_difference_x < 1e-10); + /// assert!(abs_difference_y < 1e-10); + /// + /// assert!(f64::NAN.abs().is_nan()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn abs(self) -> f64 { num::Float::abs(self) } + + /// Returns a number that represents the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - `NAN` if the number is `NAN` + /// + /// ``` + /// use std::f64; + /// + /// let f = 3.5_f64; + /// + /// assert_eq!(f.signum(), 1.0); + /// assert_eq!(f64::NEG_INFINITY.signum(), -1.0); + /// + /// assert!(f64::NAN.signum().is_nan()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn signum(self) -> f64 { num::Float::signum(self) } + + /// Returns `true` if `self`'s sign bit is positive, including + /// `+0.0` and `INFINITY`. + /// + /// ``` + /// use std::f64; + /// + /// let nan: f64 = f64::NAN; + /// + /// let f = 7.0_f64; + /// let g = -7.0_f64; + /// + /// assert!(f.is_sign_positive()); + /// assert!(!g.is_sign_positive()); + /// // 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) } + + #[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) } + + /// Returns `true` if `self`'s sign is negative, including `-0.0` + /// and `NEG_INFINITY`. + /// + /// ``` + /// use std::f64; + /// + /// let nan = f64::NAN; + /// + /// let f = 7.0_f64; + /// let g = -7.0_f64; + /// + /// assert!(!f.is_sign_negative()); + /// assert!(g.is_sign_negative()); + /// // 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) } + + #[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) } + + /// Fused multiply-add. Computes `(self * a) + b` with only one rounding + /// error. This produces a more accurate result with better performance than + /// a separate multiplication operation followed by an add. + /// + /// ``` + /// let m = 10.0_f64; + /// let x = 4.0_f64; + /// let b = 60.0_f64; + /// + /// // 100.0 + /// let abs_difference = (m.mul_add(x, b) - (m*x + b)).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn mul_add(self, a: f64, b: f64) -> f64 { + unsafe { intrinsics::fmaf64(self, a, b) } + } + + /// Takes the reciprocal (inverse) of a number, `1/x`. + /// + /// ``` + /// let x = 2.0_f64; + /// let abs_difference = (x.recip() - (1.0/x)).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn recip(self) -> f64 { num::Float::recip(self) } + + /// Raises a number to an integer power. + /// + /// Using this function is generally faster than using `powf` + /// + /// ``` + /// let x = 2.0_f64; + /// let abs_difference = (x.powi(2) - x*x).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn powi(self, n: i32) -> f64 { num::Float::powi(self, n) } + + /// Raises a number to a floating point power. + /// + /// ``` + /// let x = 2.0_f64; + /// let abs_difference = (x.powf(2.0) - x*x).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn powf(self, n: f64) -> f64 { + unsafe { intrinsics::powf64(self, n) } + } + + /// Takes the square root of a number. + /// + /// Returns NaN if `self` is a negative number. + /// + /// ``` + /// let positive = 4.0_f64; + /// let negative = -4.0_f64; + /// + /// let abs_difference = (positive.sqrt() - 2.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// assert!(negative.sqrt().is_nan()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn sqrt(self) -> f64 { + if self < 0.0 { + NAN + } else { + unsafe { intrinsics::sqrtf64(self) } + } + } + + /// Returns `e^(self)`, (the exponential function). + /// + /// ``` + /// let one = 1.0_f64; + /// // e^1 + /// let e = one.exp(); + /// + /// // ln(e) - 1 == 0 + /// let abs_difference = (e.ln() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn exp(self) -> f64 { + unsafe { intrinsics::expf64(self) } + } + + /// Returns `2^(self)`. + /// + /// ``` + /// let f = 2.0_f64; + /// + /// // 2^2 - 4 == 0 + /// let abs_difference = (f.exp2() - 4.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn exp2(self) -> f64 { + unsafe { intrinsics::exp2f64(self) } + } + + /// Returns the natural logarithm of the number. + /// + /// ``` + /// let one = 1.0_f64; + /// // e^1 + /// let e = one.exp(); + /// + /// // ln(e) - 1 == 0 + /// let abs_difference = (e.ln() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn ln(self) -> f64 { + self.log_wrapper(|n| { unsafe { intrinsics::logf64(n) } }) + } + + /// Returns the logarithm of the number with respect to an arbitrary base. + /// + /// ``` + /// let ten = 10.0_f64; + /// let two = 2.0_f64; + /// + /// // log10(10) - 1 == 0 + /// let abs_difference_10 = (ten.log(10.0) - 1.0).abs(); + /// + /// // log2(2) - 1 == 0 + /// let abs_difference_2 = (two.log(2.0) - 1.0).abs(); + /// + /// 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() } + + /// Returns the base 2 logarithm of the number. + /// + /// ``` + /// let two = 2.0_f64; + /// + /// // log2(2) - 1 == 0 + /// let abs_difference = (two.log2() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn log2(self) -> f64 { + self.log_wrapper(|n| { + #[cfg(target_os = "android")] + return ::sys::android::log2f64(n); + #[cfg(not(target_os = "android"))] + return unsafe { intrinsics::log2f64(n) }; + }) + } + + /// Returns the base 10 logarithm of the number. + /// + /// ``` + /// let ten = 10.0_f64; + /// + /// // log10(10) - 1 == 0 + /// let abs_difference = (ten.log10() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn log10(self) -> f64 { + self.log_wrapper(|n| { unsafe { intrinsics::log10f64(n) } }) + } + + /// Converts radians to degrees. + /// + /// ``` + /// use std::f64::consts; + /// + /// let angle = consts::PI; + /// + /// let abs_difference = (angle.to_degrees() - 180.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn to_degrees(self) -> f64 { num::Float::to_degrees(self) } + + /// Converts degrees to radians. + /// + /// ``` + /// use std::f64::consts; + /// + /// let angle = 180.0_f64; + /// + /// let abs_difference = (angle.to_radians() - consts::PI).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn to_radians(self) -> f64 { num::Float::to_radians(self) } + + /// Constructs a floating point number of `x*2^exp`. + /// + /// ``` + /// #![feature(float_extras)] + /// + /// // 3*2^2 - 12 == 0 + /// let abs_difference = (f64::ldexp(3.0, 2) - 12.0).abs(); + /// + /// 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) } + } + + /// Breaks the number into a normalized fraction and a base-2 exponent, + /// satisfying: + /// + /// * `self = x * 2^exp` + /// * `0.5 <= abs(x) < 1.0` + /// + /// ``` + /// #![feature(float_extras)] + /// + /// let x = 4.0_f64; + /// + /// // (1/2)*2^3 -> 1 * 8/2 -> 4.0 + /// let f = x.frexp(); + /// let abs_difference_0 = (f.0 - 0.5).abs(); + /// let abs_difference_1 = (f.1 as f64 - 3.0).abs(); + /// + /// 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 { + let mut exp = 0; + let x = cmath::frexp(self, &mut exp); + (x, exp as isize) + } + } + + /// Returns the next representable floating-point value in the direction of + /// `other`. + /// + /// ``` + /// #![feature(float_extras)] + /// + /// let x = 1.0f64; + /// + /// let abs_diff = (x.next_after(2.0) - 1.0000000000000002220446049250313_f64).abs(); + /// + /// 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) } + } + + /// Returns the maximum of the two numbers. + /// + /// ``` + /// let x = 1.0_f64; + /// let y = 2.0_f64; + /// + /// assert_eq!(x.max(y), y); + /// ``` + /// + /// 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) } + } + + /// Returns the minimum of the two numbers. + /// + /// ``` + /// let x = 1.0_f64; + /// let y = 2.0_f64; + /// + /// assert_eq!(x.min(y), x); + /// ``` + /// + /// 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) } + } + + /// The positive difference of two numbers. + /// + /// * If `self <= other`: `0:0` + /// * Else: `self - other` + /// + /// ``` + /// let x = 3.0_f64; + /// let y = -3.0_f64; + /// + /// let abs_difference_x = (x.abs_sub(1.0) - 2.0).abs(); + /// let abs_difference_y = (y.abs_sub(1.0) - 0.0).abs(); + /// + /// assert!(abs_difference_x < 1e-10); + /// assert!(abs_difference_y < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[rustc_deprecated(since = "1.10.0", + reason = "you probably meant `(self - other).abs()`: \ + this operation is `(self - other).max(0.0)` (also \ + known as `fdim` in C). If you truly need the positive \ + difference, consider using that expression or the C function \ + `fdim`, depending on how you wish to handle NaN (please consider \ + filing an issue describing your use-case too).")] + pub fn abs_sub(self, other: f64) -> f64 { + unsafe { cmath::fdim(self, other) } + } + + /// Takes the cubic root of a number. + /// + /// ``` + /// let x = 8.0_f64; + /// + /// // x^(1/3) - 2 == 0 + /// let abs_difference = (x.cbrt() - 2.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn cbrt(self) -> f64 { + unsafe { cmath::cbrt(self) } + } + + /// Calculates the length of the hypotenuse of a right-angle triangle given + /// legs of length `x` and `y`. + /// + /// ``` + /// let x = 2.0_f64; + /// let y = 3.0_f64; + /// + /// // sqrt(x^2 + y^2) + /// let abs_difference = (x.hypot(y) - (x.powi(2) + y.powi(2)).sqrt()).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn hypot(self, other: f64) -> f64 { + unsafe { cmath::hypot(self, other) } + } + + /// Computes the sine of a number (in radians). + /// + /// ``` + /// use std::f64; + /// + /// let x = f64::consts::PI/2.0; + /// + /// let abs_difference = (x.sin() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn sin(self) -> f64 { + unsafe { intrinsics::sinf64(self) } + } + + /// Computes the cosine of a number (in radians). + /// + /// ``` + /// use std::f64; + /// + /// let x = 2.0*f64::consts::PI; + /// + /// let abs_difference = (x.cos() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn cos(self) -> f64 { + unsafe { intrinsics::cosf64(self) } + } + + /// Computes the tangent of a number (in radians). + /// + /// ``` + /// use std::f64; + /// + /// let x = f64::consts::PI/4.0; + /// let abs_difference = (x.tan() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-14); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn tan(self) -> f64 { + unsafe { cmath::tan(self) } + } + + /// Computes the arcsine of a number. Return value is in radians in + /// the range [-pi/2, pi/2] or NaN if the number is outside the range + /// [-1, 1]. + /// + /// ``` + /// use std::f64; + /// + /// let f = f64::consts::PI / 2.0; + /// + /// // asin(sin(pi/2)) + /// let abs_difference = (f.sin().asin() - f64::consts::PI / 2.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn asin(self) -> f64 { + unsafe { cmath::asin(self) } + } + + /// Computes the arccosine of a number. Return value is in radians in + /// the range [0, pi] or NaN if the number is outside the range + /// [-1, 1]. + /// + /// ``` + /// use std::f64; + /// + /// let f = f64::consts::PI / 4.0; + /// + /// // acos(cos(pi/4)) + /// let abs_difference = (f.cos().acos() - f64::consts::PI / 4.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn acos(self) -> f64 { + unsafe { cmath::acos(self) } + } + + /// Computes the arctangent of a number. Return value is in radians in the + /// range [-pi/2, pi/2]; + /// + /// ``` + /// let f = 1.0_f64; + /// + /// // atan(tan(1)) + /// let abs_difference = (f.tan().atan() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn atan(self) -> f64 { + unsafe { cmath::atan(self) } + } + + /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`). + /// + /// * `x = 0`, `y = 0`: `0` + /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]` + /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` + /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` + /// + /// ``` + /// use std::f64; + /// + /// let pi = f64::consts::PI; + /// // All angles from horizontal right (+x) + /// // 45 deg counter-clockwise + /// let x1 = 3.0_f64; + /// let y1 = -3.0_f64; + /// + /// // 135 deg clockwise + /// let x2 = -3.0_f64; + /// let y2 = 3.0_f64; + /// + /// let abs_difference_1 = (y1.atan2(x1) - (-pi/4.0)).abs(); + /// let abs_difference_2 = (y2.atan2(x2) - 3.0*pi/4.0).abs(); + /// + /// assert!(abs_difference_1 < 1e-10); + /// assert!(abs_difference_2 < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn atan2(self, other: f64) -> f64 { + unsafe { cmath::atan2(self, other) } + } + + /// Simultaneously computes the sine and cosine of the number, `x`. Returns + /// `(sin(x), cos(x))`. + /// + /// ``` + /// use std::f64; + /// + /// let x = f64::consts::PI/4.0; + /// let f = x.sin_cos(); + /// + /// let abs_difference_0 = (f.0 - x.sin()).abs(); + /// let abs_difference_1 = (f.1 - x.cos()).abs(); + /// + /// assert!(abs_difference_0 < 1e-10); + /// assert!(abs_difference_1 < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn sin_cos(self) -> (f64, f64) { + (self.sin(), self.cos()) + } + + /// Returns `e^(self) - 1` in a way that is accurate even if the + /// number is close to zero. + /// + /// ``` + /// let x = 7.0_f64; + /// + /// // e^(ln(7)) - 1 + /// let abs_difference = (x.ln().exp_m1() - 6.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn exp_m1(self) -> f64 { + unsafe { cmath::expm1(self) } + } + + /// Returns `ln(1+n)` (natural logarithm) more accurately than if + /// the operations were performed separately. + /// + /// ``` + /// use std::f64; + /// + /// let x = f64::consts::E - 1.0; + /// + /// // ln(1 + (e - 1)) == ln(e) == 1 + /// let abs_difference = (x.ln_1p() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn ln_1p(self) -> f64 { + unsafe { cmath::log1p(self) } + } + + /// Hyperbolic sine function. + /// + /// ``` + /// use std::f64; + /// + /// let e = f64::consts::E; + /// let x = 1.0_f64; + /// + /// let f = x.sinh(); + /// // Solving sinh() at 1 gives `(e^2-1)/(2e)` + /// let g = (e*e - 1.0)/(2.0*e); + /// let abs_difference = (f - g).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn sinh(self) -> f64 { + unsafe { cmath::sinh(self) } + } + + /// Hyperbolic cosine function. + /// + /// ``` + /// use std::f64; + /// + /// let e = f64::consts::E; + /// let x = 1.0_f64; + /// let f = x.cosh(); + /// // Solving cosh() at 1 gives this result + /// let g = (e*e + 1.0)/(2.0*e); + /// let abs_difference = (f - g).abs(); + /// + /// // Same result + /// assert!(abs_difference < 1.0e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn cosh(self) -> f64 { + unsafe { cmath::cosh(self) } + } + + /// Hyperbolic tangent function. + /// + /// ``` + /// use std::f64; + /// + /// let e = f64::consts::E; + /// let x = 1.0_f64; + /// + /// let f = x.tanh(); + /// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))` + /// let g = (1.0 - e.powi(-2))/(1.0 + e.powi(-2)); + /// let abs_difference = (f - g).abs(); + /// + /// assert!(abs_difference < 1.0e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn tanh(self) -> f64 { + unsafe { cmath::tanh(self) } + } + + /// Inverse hyperbolic sine function. + /// + /// ``` + /// let x = 1.0_f64; + /// let f = x.sinh().asinh(); + /// + /// let abs_difference = (f - x).abs(); + /// + /// assert!(abs_difference < 1.0e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn asinh(self) -> f64 { + if self == NEG_INFINITY { + NEG_INFINITY + } else { + (self + ((self * self) + 1.0).sqrt()).ln() + } + } + + /// Inverse hyperbolic cosine function. + /// + /// ``` + /// let x = 1.0_f64; + /// let f = x.cosh().acosh(); + /// + /// let abs_difference = (f - x).abs(); + /// + /// assert!(abs_difference < 1.0e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn acosh(self) -> f64 { + match self { + x if x < 1.0 => NAN, + x => (x + ((x * x) - 1.0).sqrt()).ln(), + } + } + + /// Inverse hyperbolic tangent function. + /// + /// ``` + /// use std::f64; + /// + /// let e = f64::consts::E; + /// let f = e.tanh().atanh(); + /// + /// let abs_difference = (f - e).abs(); + /// + /// assert!(abs_difference < 1.0e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn atanh(self) -> f64 { + 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() + } + + // Solaris/Illumos requires a wrapper around log, log2, and log10 functions + // because of their non-standard behavior (e.g. log(-n) returns -Inf instead + // of expected NaN). + fn log_wrapper f64>(self, log_fn: F) -> f64 { + if !cfg!(target_os = "solaris") { + log_fn(self) + } else { + if self.is_finite() { + if self > 0.0 { + log_fn(self) + } else if self == 0.0 { + NEG_INFINITY // log(0) = -Inf + } else { + NAN // log(-n) = NaN + } + } else if self.is_nan() { + self // log(NaN) = NaN + } else if self > 0.0 { + self // log(Inf) = Inf + } else { + NAN // log(-Inf) = NaN + } + } + } +} + +#[cfg(test)] +mod tests { + use f64; + use f64::*; + use num::*; + use num::FpCategory as Fp; + + #[test] + fn test_num_f64() { + test_num(10f64, 2f64); + } + + #[test] + fn test_min_nan() { + assert_eq!(NAN.min(2.0), 2.0); + assert_eq!(2.0f64.min(NAN), 2.0); + } + + #[test] + fn test_max_nan() { + assert_eq!(NAN.max(2.0), 2.0); + assert_eq!(2.0f64.max(NAN), 2.0); + } + + #[test] + fn test_nan() { + let nan: f64 = NAN; + assert!(nan.is_nan()); + assert!(!nan.is_infinite()); + assert!(!nan.is_finite()); + assert!(!nan.is_normal()); + assert!(!nan.is_sign_positive()); + assert!(!nan.is_sign_negative()); + assert_eq!(Fp::Nan, nan.classify()); + } + + #[test] + fn test_infinity() { + let inf: f64 = INFINITY; + assert!(inf.is_infinite()); + assert!(!inf.is_finite()); + assert!(inf.is_sign_positive()); + assert!(!inf.is_sign_negative()); + assert!(!inf.is_nan()); + assert!(!inf.is_normal()); + assert_eq!(Fp::Infinite, inf.classify()); + } + + #[test] + fn test_neg_infinity() { + let neg_inf: f64 = NEG_INFINITY; + assert!(neg_inf.is_infinite()); + assert!(!neg_inf.is_finite()); + assert!(!neg_inf.is_sign_positive()); + assert!(neg_inf.is_sign_negative()); + assert!(!neg_inf.is_nan()); + assert!(!neg_inf.is_normal()); + assert_eq!(Fp::Infinite, neg_inf.classify()); + } + + #[test] + fn test_zero() { + let zero: f64 = 0.0f64; + assert_eq!(0.0, zero); + assert!(!zero.is_infinite()); + assert!(zero.is_finite()); + assert!(zero.is_sign_positive()); + assert!(!zero.is_sign_negative()); + assert!(!zero.is_nan()); + assert!(!zero.is_normal()); + assert_eq!(Fp::Zero, zero.classify()); + } + + #[test] + fn test_neg_zero() { + let neg_zero: f64 = -0.0; + assert_eq!(0.0, neg_zero); + assert!(!neg_zero.is_infinite()); + assert!(neg_zero.is_finite()); + assert!(!neg_zero.is_sign_positive()); + assert!(neg_zero.is_sign_negative()); + assert!(!neg_zero.is_nan()); + assert!(!neg_zero.is_normal()); + assert_eq!(Fp::Zero, neg_zero.classify()); + } + + #[test] + fn test_one() { + let one: f64 = 1.0f64; + assert_eq!(1.0, one); + assert!(!one.is_infinite()); + assert!(one.is_finite()); + assert!(one.is_sign_positive()); + assert!(!one.is_sign_negative()); + assert!(!one.is_nan()); + assert!(one.is_normal()); + assert_eq!(Fp::Normal, one.classify()); + } + + #[test] + fn test_is_nan() { + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + assert!(nan.is_nan()); + assert!(!0.0f64.is_nan()); + assert!(!5.3f64.is_nan()); + assert!(!(-10.732f64).is_nan()); + assert!(!inf.is_nan()); + assert!(!neg_inf.is_nan()); + } + + #[test] + fn test_is_infinite() { + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + assert!(!nan.is_infinite()); + assert!(inf.is_infinite()); + assert!(neg_inf.is_infinite()); + assert!(!0.0f64.is_infinite()); + assert!(!42.8f64.is_infinite()); + assert!(!(-109.2f64).is_infinite()); + } + + #[test] + fn test_is_finite() { + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + assert!(!nan.is_finite()); + assert!(!inf.is_finite()); + assert!(!neg_inf.is_finite()); + assert!(0.0f64.is_finite()); + assert!(42.8f64.is_finite()); + assert!((-109.2f64).is_finite()); + } + + #[test] + fn test_is_normal() { + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + let zero: f64 = 0.0f64; + let neg_zero: f64 = -0.0; + assert!(!nan.is_normal()); + assert!(!inf.is_normal()); + assert!(!neg_inf.is_normal()); + assert!(!zero.is_normal()); + assert!(!neg_zero.is_normal()); + assert!(1f64.is_normal()); + assert!(1e-307f64.is_normal()); + assert!(!1e-308f64.is_normal()); + } + + #[test] + fn test_classify() { + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + let zero: f64 = 0.0f64; + let neg_zero: f64 = -0.0; + assert_eq!(nan.classify(), Fp::Nan); + assert_eq!(inf.classify(), Fp::Infinite); + assert_eq!(neg_inf.classify(), Fp::Infinite); + assert_eq!(zero.classify(), Fp::Zero); + assert_eq!(neg_zero.classify(), Fp::Zero); + assert_eq!(1e-307f64.classify(), Fp::Normal); + assert_eq!(1e-308f64.classify(), Fp::Subnormal); + } + + #[test] + #[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!(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)); + assert_eq!(INFINITY.integer_decode(), (4503599627370496, 972, 1)); + assert_eq!(NEG_INFINITY.integer_decode(), (4503599627370496, 972, -1)); + + // Ignore the "sign" (quiet / signalling flag) of NAN. + // It can vary between runtime operations and LLVM folding. + let (nan_m, nan_e, _nan_s) = NAN.integer_decode(); + assert_eq!((nan_m, nan_e), (6755399441055744, 972)); + } + + #[test] + fn test_floor() { + assert_approx_eq!(1.0f64.floor(), 1.0f64); + assert_approx_eq!(1.3f64.floor(), 1.0f64); + assert_approx_eq!(1.5f64.floor(), 1.0f64); + assert_approx_eq!(1.7f64.floor(), 1.0f64); + assert_approx_eq!(0.0f64.floor(), 0.0f64); + assert_approx_eq!((-0.0f64).floor(), -0.0f64); + assert_approx_eq!((-1.0f64).floor(), -1.0f64); + assert_approx_eq!((-1.3f64).floor(), -2.0f64); + assert_approx_eq!((-1.5f64).floor(), -2.0f64); + assert_approx_eq!((-1.7f64).floor(), -2.0f64); + } + + #[test] + fn test_ceil() { + assert_approx_eq!(1.0f64.ceil(), 1.0f64); + assert_approx_eq!(1.3f64.ceil(), 2.0f64); + assert_approx_eq!(1.5f64.ceil(), 2.0f64); + assert_approx_eq!(1.7f64.ceil(), 2.0f64); + assert_approx_eq!(0.0f64.ceil(), 0.0f64); + assert_approx_eq!((-0.0f64).ceil(), -0.0f64); + assert_approx_eq!((-1.0f64).ceil(), -1.0f64); + assert_approx_eq!((-1.3f64).ceil(), -1.0f64); + assert_approx_eq!((-1.5f64).ceil(), -1.0f64); + assert_approx_eq!((-1.7f64).ceil(), -1.0f64); + } + + #[test] + fn test_round() { + assert_approx_eq!(1.0f64.round(), 1.0f64); + assert_approx_eq!(1.3f64.round(), 1.0f64); + assert_approx_eq!(1.5f64.round(), 2.0f64); + assert_approx_eq!(1.7f64.round(), 2.0f64); + assert_approx_eq!(0.0f64.round(), 0.0f64); + assert_approx_eq!((-0.0f64).round(), -0.0f64); + assert_approx_eq!((-1.0f64).round(), -1.0f64); + assert_approx_eq!((-1.3f64).round(), -1.0f64); + assert_approx_eq!((-1.5f64).round(), -2.0f64); + assert_approx_eq!((-1.7f64).round(), -2.0f64); + } + + #[test] + fn test_trunc() { + assert_approx_eq!(1.0f64.trunc(), 1.0f64); + assert_approx_eq!(1.3f64.trunc(), 1.0f64); + assert_approx_eq!(1.5f64.trunc(), 1.0f64); + assert_approx_eq!(1.7f64.trunc(), 1.0f64); + assert_approx_eq!(0.0f64.trunc(), 0.0f64); + assert_approx_eq!((-0.0f64).trunc(), -0.0f64); + assert_approx_eq!((-1.0f64).trunc(), -1.0f64); + assert_approx_eq!((-1.3f64).trunc(), -1.0f64); + assert_approx_eq!((-1.5f64).trunc(), -1.0f64); + assert_approx_eq!((-1.7f64).trunc(), -1.0f64); + } + + #[test] + fn test_fract() { + assert_approx_eq!(1.0f64.fract(), 0.0f64); + assert_approx_eq!(1.3f64.fract(), 0.3f64); + assert_approx_eq!(1.5f64.fract(), 0.5f64); + assert_approx_eq!(1.7f64.fract(), 0.7f64); + assert_approx_eq!(0.0f64.fract(), 0.0f64); + assert_approx_eq!((-0.0f64).fract(), -0.0f64); + assert_approx_eq!((-1.0f64).fract(), -0.0f64); + assert_approx_eq!((-1.3f64).fract(), -0.3f64); + assert_approx_eq!((-1.5f64).fract(), -0.5f64); + assert_approx_eq!((-1.7f64).fract(), -0.7f64); + } + + #[test] + fn test_abs() { + assert_eq!(INFINITY.abs(), INFINITY); + assert_eq!(1f64.abs(), 1f64); + assert_eq!(0f64.abs(), 0f64); + assert_eq!((-0f64).abs(), 0f64); + assert_eq!((-1f64).abs(), 1f64); + assert_eq!(NEG_INFINITY.abs(), INFINITY); + assert_eq!((1f64/NEG_INFINITY).abs(), 0f64); + assert!(NAN.abs().is_nan()); + } + + #[test] + fn test_signum() { + assert_eq!(INFINITY.signum(), 1f64); + assert_eq!(1f64.signum(), 1f64); + assert_eq!(0f64.signum(), 1f64); + assert_eq!((-0f64).signum(), -1f64); + assert_eq!((-1f64).signum(), -1f64); + assert_eq!(NEG_INFINITY.signum(), -1f64); + assert_eq!((1f64/NEG_INFINITY).signum(), -1f64); + assert!(NAN.signum().is_nan()); + } + + #[test] + fn test_is_sign_positive() { + assert!(INFINITY.is_sign_positive()); + assert!(1f64.is_sign_positive()); + assert!(0f64.is_sign_positive()); + assert!(!(-0f64).is_sign_positive()); + assert!(!(-1f64).is_sign_positive()); + assert!(!NEG_INFINITY.is_sign_positive()); + assert!(!(1f64/NEG_INFINITY).is_sign_positive()); + assert!(!NAN.is_sign_positive()); + } + + #[test] + fn test_is_sign_negative() { + assert!(!INFINITY.is_sign_negative()); + assert!(!1f64.is_sign_negative()); + assert!(!0f64.is_sign_negative()); + assert!((-0f64).is_sign_negative()); + assert!((-1f64).is_sign_negative()); + assert!(NEG_INFINITY.is_sign_negative()); + assert!((1f64/NEG_INFINITY).is_sign_negative()); + assert!(!NAN.is_sign_negative()); + } + + #[test] + fn test_mul_add() { + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + assert_approx_eq!(12.3f64.mul_add(4.5, 6.7), 62.05); + assert_approx_eq!((-12.3f64).mul_add(-4.5, -6.7), 48.65); + assert_approx_eq!(0.0f64.mul_add(8.9, 1.2), 1.2); + assert_approx_eq!(3.4f64.mul_add(-0.0, 5.6), 5.6); + assert!(nan.mul_add(7.8, 9.0).is_nan()); + assert_eq!(inf.mul_add(7.8, 9.0), inf); + assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf); + assert_eq!(8.9f64.mul_add(inf, 3.2), inf); + assert_eq!((-3.2f64).mul_add(2.4, neg_inf), neg_inf); + } + + #[test] + fn test_recip() { + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + assert_eq!(1.0f64.recip(), 1.0); + assert_eq!(2.0f64.recip(), 0.5); + assert_eq!((-0.4f64).recip(), -2.5); + assert_eq!(0.0f64.recip(), inf); + assert!(nan.recip().is_nan()); + assert_eq!(inf.recip(), 0.0); + assert_eq!(neg_inf.recip(), 0.0); + } + + #[test] + fn test_powi() { + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + assert_eq!(1.0f64.powi(1), 1.0); + assert_approx_eq!((-3.1f64).powi(2), 9.61); + assert_approx_eq!(5.9f64.powi(-2), 0.028727); + assert_eq!(8.3f64.powi(0), 1.0); + assert!(nan.powi(2).is_nan()); + assert_eq!(inf.powi(3), inf); + assert_eq!(neg_inf.powi(2), inf); + } + + #[test] + fn test_powf() { + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + assert_eq!(1.0f64.powf(1.0), 1.0); + assert_approx_eq!(3.4f64.powf(4.5), 246.408183); + assert_approx_eq!(2.7f64.powf(-3.2), 0.041652); + assert_approx_eq!((-3.1f64).powf(2.0), 9.61); + assert_approx_eq!(5.9f64.powf(-2.0), 0.028727); + assert_eq!(8.3f64.powf(0.0), 1.0); + assert!(nan.powf(2.0).is_nan()); + assert_eq!(inf.powf(2.0), inf); + assert_eq!(neg_inf.powf(3.0), neg_inf); + } + + #[test] + fn test_sqrt_domain() { + assert!(NAN.sqrt().is_nan()); + assert!(NEG_INFINITY.sqrt().is_nan()); + assert!((-1.0f64).sqrt().is_nan()); + assert_eq!((-0.0f64).sqrt(), -0.0); + assert_eq!(0.0f64.sqrt(), 0.0); + assert_eq!(1.0f64.sqrt(), 1.0); + assert_eq!(INFINITY.sqrt(), INFINITY); + } + + #[test] + fn test_exp() { + assert_eq!(1.0, 0.0f64.exp()); + assert_approx_eq!(2.718282, 1.0f64.exp()); + assert_approx_eq!(148.413159, 5.0f64.exp()); + + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = NAN; + assert_eq!(inf, inf.exp()); + assert_eq!(0.0, neg_inf.exp()); + assert!(nan.exp().is_nan()); + } + + #[test] + fn test_exp2() { + assert_eq!(32.0, 5.0f64.exp2()); + assert_eq!(1.0, 0.0f64.exp2()); + + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = NAN; + assert_eq!(inf, inf.exp2()); + assert_eq!(0.0, neg_inf.exp2()); + assert!(nan.exp2().is_nan()); + } + + #[test] + fn test_ln() { + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + assert_approx_eq!(1.0f64.exp().ln(), 1.0); + assert!(nan.ln().is_nan()); + assert_eq!(inf.ln(), inf); + assert!(neg_inf.ln().is_nan()); + assert!((-2.3f64).ln().is_nan()); + assert_eq!((-0.0f64).ln(), neg_inf); + assert_eq!(0.0f64.ln(), neg_inf); + assert_approx_eq!(4.0f64.ln(), 1.386294); + } + + #[test] + fn test_log() { + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + assert_eq!(10.0f64.log(10.0), 1.0); + assert_approx_eq!(2.3f64.log(3.5), 0.664858); + assert_eq!(1.0f64.exp().log(1.0f64.exp()), 1.0); + assert!(1.0f64.log(1.0).is_nan()); + assert!(1.0f64.log(-13.9).is_nan()); + assert!(nan.log(2.3).is_nan()); + assert_eq!(inf.log(10.0), inf); + assert!(neg_inf.log(8.8).is_nan()); + assert!((-2.3f64).log(0.1).is_nan()); + assert_eq!((-0.0f64).log(2.0), neg_inf); + assert_eq!(0.0f64.log(7.0), neg_inf); + } + + #[test] + fn test_log2() { + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + assert_approx_eq!(10.0f64.log2(), 3.321928); + assert_approx_eq!(2.3f64.log2(), 1.201634); + assert_approx_eq!(1.0f64.exp().log2(), 1.442695); + assert!(nan.log2().is_nan()); + assert_eq!(inf.log2(), inf); + assert!(neg_inf.log2().is_nan()); + assert!((-2.3f64).log2().is_nan()); + assert_eq!((-0.0f64).log2(), neg_inf); + assert_eq!(0.0f64.log2(), neg_inf); + } + + #[test] + fn test_log10() { + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + assert_eq!(10.0f64.log10(), 1.0); + assert_approx_eq!(2.3f64.log10(), 0.361728); + assert_approx_eq!(1.0f64.exp().log10(), 0.434294); + assert_eq!(1.0f64.log10(), 0.0); + assert!(nan.log10().is_nan()); + assert_eq!(inf.log10(), inf); + assert!(neg_inf.log10().is_nan()); + assert!((-2.3f64).log10().is_nan()); + assert_eq!((-0.0f64).log10(), neg_inf); + assert_eq!(0.0f64.log10(), neg_inf); + } + + #[test] + fn test_to_degrees() { + let pi: f64 = consts::PI; + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + assert_eq!(0.0f64.to_degrees(), 0.0); + assert_approx_eq!((-5.8f64).to_degrees(), -332.315521); + assert_eq!(pi.to_degrees(), 180.0); + assert!(nan.to_degrees().is_nan()); + assert_eq!(inf.to_degrees(), inf); + assert_eq!(neg_inf.to_degrees(), neg_inf); + } + + #[test] + fn test_to_radians() { + let pi: f64 = consts::PI; + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + assert_eq!(0.0f64.to_radians(), 0.0); + assert_approx_eq!(154.6f64.to_radians(), 2.698279); + assert_approx_eq!((-332.31f64).to_radians(), -5.799903); + assert_eq!(180.0f64.to_radians(), pi); + assert!(nan.to_radians().is_nan()); + assert_eq!(inf.to_radians(), inf); + assert_eq!(neg_inf.to_radians(), neg_inf); + } + + #[test] + #[allow(deprecated)] + fn test_ldexp() { + let f1 = 2.0f64.powi(-123); + let f2 = 2.0f64.powi(-111); + let f3 = 1.75 * 2.0f64.powi(-12); + assert_eq!(f64::ldexp(1f64, -123), f1); + assert_eq!(f64::ldexp(1f64, -111), f2); + assert_eq!(f64::ldexp(1.75f64, -12), f3); + + assert_eq!(f64::ldexp(0f64, -123), 0f64); + assert_eq!(f64::ldexp(-0f64, -123), -0f64); + + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = NAN; + assert_eq!(f64::ldexp(inf, -123), inf); + assert_eq!(f64::ldexp(neg_inf, -123), neg_inf); + assert!(f64::ldexp(nan, -123).is_nan()); + } + + #[test] + #[allow(deprecated)] + fn test_frexp() { + let f1 = 2.0f64.powi(-123); + let f2 = 2.0f64.powi(-111); + let f3 = 1.75 * 2.0f64.powi(-123); + let (x1, exp1) = f1.frexp(); + let (x2, exp2) = f2.frexp(); + let (x3, exp3) = f3.frexp(); + assert_eq!((x1, exp1), (0.5f64, -122)); + assert_eq!((x2, exp2), (0.5f64, -110)); + assert_eq!((x3, exp3), (0.875f64, -122)); + assert_eq!(f64::ldexp(x1, exp1), f1); + assert_eq!(f64::ldexp(x2, exp2), f2); + assert_eq!(f64::ldexp(x3, exp3), f3); + + assert_eq!(0f64.frexp(), (0f64, 0)); + assert_eq!((-0f64).frexp(), (-0f64, 0)); + } + + #[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() }) + } + + #[test] + fn test_asinh() { + assert_eq!(0.0f64.asinh(), 0.0f64); + assert_eq!((-0.0f64).asinh(), -0.0f64); + + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = NAN; + assert_eq!(inf.asinh(), inf); + assert_eq!(neg_inf.asinh(), neg_inf); + assert!(nan.asinh().is_nan()); + assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64); + assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64); + } + + #[test] + fn test_acosh() { + assert_eq!(1.0f64.acosh(), 0.0f64); + assert!(0.999f64.acosh().is_nan()); + + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = NAN; + assert_eq!(inf.acosh(), inf); + assert!(neg_inf.acosh().is_nan()); + assert!(nan.acosh().is_nan()); + assert_approx_eq!(2.0f64.acosh(), 1.31695789692481670862504634730796844f64); + assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64); + } + + #[test] + fn test_atanh() { + assert_eq!(0.0f64.atanh(), 0.0f64); + assert_eq!((-0.0f64).atanh(), -0.0f64); + + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = NAN; + assert_eq!(1.0f64.atanh(), inf); + assert_eq!((-1.0f64).atanh(), neg_inf); + assert!(2f64.atanh().atanh().is_nan()); + assert!((-2f64).atanh().atanh().is_nan()); + assert!(inf.atanh().is_nan()); + assert!(neg_inf.atanh().is_nan()); + assert!(nan.atanh().is_nan()); + assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64); + assert_approx_eq!((-0.5f64).atanh(), -0.54930614433405484569762261846126285f64); + } + + #[test] + fn test_real_consts() { + use super::consts; + let pi: f64 = consts::PI; + let frac_pi_2: f64 = consts::FRAC_PI_2; + let frac_pi_3: f64 = consts::FRAC_PI_3; + let frac_pi_4: f64 = consts::FRAC_PI_4; + let frac_pi_6: f64 = consts::FRAC_PI_6; + let frac_pi_8: f64 = consts::FRAC_PI_8; + let frac_1_pi: f64 = consts::FRAC_1_PI; + let frac_2_pi: f64 = consts::FRAC_2_PI; + let frac_2_sqrtpi: f64 = consts::FRAC_2_SQRT_PI; + let sqrt2: f64 = consts::SQRT_2; + let frac_1_sqrt2: f64 = consts::FRAC_1_SQRT_2; + let e: f64 = consts::E; + let log2_e: f64 = consts::LOG2_E; + let log10_e: f64 = consts::LOG10_E; + let ln_2: f64 = consts::LN_2; + let ln_10: f64 = consts::LN_10; + + assert_approx_eq!(frac_pi_2, pi / 2f64); + assert_approx_eq!(frac_pi_3, pi / 3f64); + assert_approx_eq!(frac_pi_4, pi / 4f64); + assert_approx_eq!(frac_pi_6, pi / 6f64); + assert_approx_eq!(frac_pi_8, pi / 8f64); + assert_approx_eq!(frac_1_pi, 1f64 / pi); + assert_approx_eq!(frac_2_pi, 2f64 / pi); + assert_approx_eq!(frac_2_sqrtpi, 2f64 / pi.sqrt()); + assert_approx_eq!(sqrt2, 2f64.sqrt()); + assert_approx_eq!(frac_1_sqrt2, 1f64 / 2f64.sqrt()); + assert_approx_eq!(log2_e, e.log2()); + assert_approx_eq!(log10_e, e.log10()); + assert_approx_eq!(ln_2, 2f64.ln()); + assert_approx_eq!(ln_10, 10f64.ln()); + } +} diff --git a/ctr-std/src/ffi/c_str.rs b/ctr-std/src/ffi/c_str.rs new file mode 100644 index 0000000..ad40660 --- /dev/null +++ b/ctr-std/src/ffi/c_str.rs @@ -0,0 +1,849 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ascii; +use borrow::{Cow, Borrow}; +use cmp::Ordering; +use error::Error; +use fmt::{self, Write}; +use io; +use libc::{self, c_char}; +use mem; +use memchr; +use ops; +use ptr; +use slice; +use str::{self, Utf8Error}; + +/// A type representing an owned C-compatible string +/// +/// This type serves the primary purpose of being able to safely generate a +/// C-compatible string from a Rust byte slice or vector. An instance of this +/// type is a static guarantee that the underlying bytes contain no interior 0 +/// bytes and the final byte is 0. +/// +/// A `CString` is created from either a byte slice or a byte vector. After +/// being created, a `CString` predominately inherits all of its methods from +/// the `Deref` implementation to `[c_char]`. Note that the underlying array +/// is represented as an array of `c_char` as opposed to `u8`. A `u8` slice +/// can be obtained with the `as_bytes` method. Slices produced from a `CString` +/// do *not* contain the trailing nul terminator unless otherwise specified. +/// +/// # Examples +/// +/// ```no_run +/// # fn main() { +/// use std::ffi::CString; +/// use std::os::raw::c_char; +/// +/// extern { +/// fn my_printer(s: *const c_char); +/// } +/// +/// let c_to_print = CString::new("Hello, world!").unwrap(); +/// unsafe { +/// my_printer(c_to_print.as_ptr()); +/// } +/// # } +/// ``` +/// +/// # Safety +/// +/// `CString` is intended for working with traditional C-style strings +/// (a sequence of non-null bytes terminated by a single null byte); the +/// primary use case for these kinds of strings is interoperating with C-like +/// code. Often you will need to transfer ownership to/from that external +/// code. It is strongly recommended that you thoroughly read through the +/// documentation of `CString` before use, as improper ownership management +/// of `CString` instances can lead to invalid memory accesses, memory leaks, +/// and other memory errors. + +#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct CString { + // Invariant 1: the slice ends with a zero byte and has a length of at least one. + // Invariant 2: the slice contains only one zero byte. + // Improper usage of unsafe function can break Invariant 2, but not Invariant 1. + inner: Box<[u8]>, +} + +/// Representation of a borrowed C string. +/// +/// This dynamically sized type is only safely constructed via a borrowed +/// version of an instance of `CString`. This type can be constructed from a raw +/// C string as well and represents a C string borrowed from another location. +/// +/// Note that this structure is **not** `repr(C)` and is not recommended to be +/// placed in the signatures of FFI functions. Instead safe wrappers of FFI +/// functions may leverage the unsafe `from_ptr` constructor to provide a safe +/// interface to other consumers. +/// +/// # Examples +/// +/// Inspecting a foreign C string +/// +/// ```no_run +/// use std::ffi::CStr; +/// use std::os::raw::c_char; +/// +/// extern { fn my_string() -> *const c_char; } +/// +/// unsafe { +/// let slice = CStr::from_ptr(my_string()); +/// println!("string length: {}", slice.to_bytes().len()); +/// } +/// ``` +/// +/// Passing a Rust-originating C string +/// +/// ```no_run +/// use std::ffi::{CString, CStr}; +/// use std::os::raw::c_char; +/// +/// fn work(data: &CStr) { +/// extern { fn work_with(data: *const c_char); } +/// +/// unsafe { work_with(data.as_ptr()) } +/// } +/// +/// let s = CString::new("data data data data").unwrap(); +/// work(&s); +/// ``` +/// +/// Converting a foreign C string into a Rust `String` +/// +/// ```no_run +/// use std::ffi::CStr; +/// use std::os::raw::c_char; +/// +/// extern { fn my_string() -> *const c_char; } +/// +/// fn my_string_safe() -> String { +/// unsafe { +/// CStr::from_ptr(my_string()).to_string_lossy().into_owned() +/// } +/// } +/// +/// println!("string: {}", my_string_safe()); +/// ``` +#[derive(Hash)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct CStr { + // FIXME: this should not be represented with a DST slice but rather with + // just a raw `c_char` along with some form of marker to make + // this an unsized type. Essentially `sizeof(&CStr)` should be the + // same as `sizeof(&c_char)` but `CStr` should be an unsized type. + inner: [c_char] +} + +/// An error 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, +} + +impl CString { + /// Creates a new C-compatible string from a container of bytes. + /// + /// This method will consume the provided data and use the underlying bytes + /// to construct a new string, ensuring that there is a trailing 0 byte. + /// + /// # Examples + /// + /// ```no_run + /// use std::ffi::CString; + /// use std::os::raw::c_char; + /// + /// extern { fn puts(s: *const c_char); } + /// + /// let to_print = CString::new("Hello!").unwrap(); + /// unsafe { + /// puts(to_print.as_ptr()); + /// } + /// ``` + /// + /// # Errors + /// + /// This function will return an error if the 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()) + } + + fn _new(bytes: Vec) -> Result { + match memchr::memchr(0, &bytes) { + Some(i) => Err(NulError(i, bytes)), + None => Ok(unsafe { CString::from_vec_unchecked(bytes) }), + } + } + + /// Creates a C-compatible string from a byte vector without checking for + /// interior 0 bytes. + /// + /// This method is equivalent to `new` except that no runtime assertion + /// is made that `v` contains no 0 bytes, and it requires an actual + /// byte vector, not anything that can be converted to one with Into. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::CString; + /// + /// let raw = b"foo".to_vec(); + /// unsafe { + /// let c_string = CString::from_vec_unchecked(raw); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub unsafe fn from_vec_unchecked(mut v: Vec) -> CString { + v.reserve_exact(1); + v.push(0); + CString { inner: v.into_boxed_slice() } + } + + /// Retakes ownership of a `CString` that was transferred to C. + /// + /// Additionally, the length of the string will be recalculated from the pointer. + /// + /// # Safety + /// + /// This should only ever be called with a pointer that was earlier + /// obtained by calling `into_raw` on a `CString`. Other usage (e.g. trying to take + /// ownership of a string that was allocated by foreign code) is likely to lead + /// to undefined behavior or allocator corruption. + #[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); + CString { inner: mem::transmute(slice) } + } + + /// Transfers ownership of the string to a C caller. + /// + /// The pointer must be returned to Rust and reconstituted using + /// `from_raw` to be properly deallocated. Specifically, one + /// should *not* use the standard C `free` function to deallocate + /// this string. + /// + /// Failure to call `from_raw` will lead to a memory leak. + #[stable(feature = "cstr_memory", since = "1.4.0")] + pub fn into_raw(self) -> *mut c_char { + Box::into_raw(self.into_inner()) as *mut c_char + } + + /// Converts the `CString` into a `String` if it contains valid 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 { + error: e.utf8_error(), + inner: unsafe { CString::from_vec_unchecked(e.into_bytes()) }, + }) + } + + /// Returns the underlying byte buffer. + /// + /// 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(); + debug_assert_eq!(_nul, Some(0u8)); + vec + } + + /// 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() + } + + /// Returns the contents of this `CString` as a slice of bytes. + /// + /// 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 + } + + // Bypass "move out of struct which implements `Drop` trait" restriction. + fn into_inner(self) -> Box<[u8]> { + unsafe { + let result = ptr::read(&self.inner); + mem::forget(self); + result + } + } +} + +// Turns this `CString` into an empty string to prevent +// memory unsafe code from working by accident. Inline +// to prevent LLVM from optimizing it away in debug builds. +#[stable(feature = "cstring_drop", since = "1.13.0")] +impl Drop for CString { + #[inline] + fn drop(&mut self) { + unsafe { *self.inner.get_unchecked_mut(0) = 0; } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ops::Deref for CString { + type Target = CStr; + + fn deref(&self) -> &CStr { + unsafe { mem::transmute(self.as_bytes_with_nul()) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for CString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +#[stable(feature = "cstring_into", since = "1.7.0")] +impl From for Vec { + fn from(s: CString) -> Vec { + s.into_bytes() + } +} + +#[stable(feature = "cstr_debug", since = "1.3.0")] +impl fmt::Debug for CStr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "\"")?; + for byte in self.to_bytes().iter().flat_map(|&b| ascii::escape_default(b)) { + f.write_char(byte as char)?; + } + write!(f, "\"") + } +} + +#[stable(feature = "cstr_default", since = "1.10.0")] +impl<'a> Default for &'a CStr { + fn default() -> &'a CStr { + static SLICE: &'static [c_char] = &[0]; + unsafe { CStr::from_ptr(SLICE.as_ptr()) } + } +} + +#[stable(feature = "cstr_default", since = "1.10.0")] +impl Default for CString { + /// Creates an empty `CString`. + fn default() -> CString { + let a: &CStr = Default::default(); + a.to_owned() + } +} + +#[stable(feature = "cstr_borrow", since = "1.3.0")] +impl Borrow for CString { + fn borrow(&self) -> &CStr { self } +} + +impl NulError { + /// Returns the position of the nul byte in the slice that was provided to + /// `CString::new`. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::CString; + /// + /// let nul_error = CString::new("foo\0bar").unwrap_err(); + /// assert_eq!(nul_error.nul_position(), 3); + /// + /// let nul_error = CString::new("foo bar\0").unwrap_err(); + /// assert_eq!(nul_error.nul_position(), 7); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn nul_position(&self) -> usize { self.0 } + + /// Consumes this error, returning the underlying vector of bytes which + /// generated the error in the first place. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::CString; + /// + /// let nul_error = CString::new("foo\0bar").unwrap_err(); + /// assert_eq!(nul_error.into_vec(), b"foo\0bar"); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_vec(self) -> Vec { self.1 } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for NulError { + fn description(&self) -> &str { "nul byte found in data" } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for NulError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "nul byte found in provided data at position: {}", self.0) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl From for io::Error { + fn from(_: NulError) -> io::Error { + io::Error::new(io::ErrorKind::InvalidInput, + "data provided contains a nul byte") + } +} + +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" + } + + fn cause(&self) -> Option<&Error> { + Some(&self.error) + } +} + +#[stable(feature = "cstring_into", since = "1.7.0")] +impl fmt::Display for IntoStringError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.description().fmt(f) + } +} + +impl CStr { + /// Casts a raw C string to a safe C string wrapper. + /// + /// This function will cast the provided `ptr` to the `CStr` wrapper which + /// allows inspection and interoperation of non-owned C strings. This method + /// is unsafe for a number of reasons: + /// + /// * There is no guarantee to the validity of `ptr` + /// * The returned lifetime is not guaranteed to be the actual lifetime of + /// `ptr` + /// * There is no guarantee that the memory pointed to by `ptr` contains a + /// valid nul terminator byte at the end of the string. + /// + /// > **Note**: This operation is intended to be a 0-cost cast but it is + /// > currently implemented with an up-front calculation of the length of + /// > the string. This is not guaranteed to always be the case. + /// + /// # Examples + /// + /// ```no_run + /// # fn main() { + /// use std::ffi::CStr; + /// use std::os::raw::c_char; + /// + /// extern { + /// fn my_string() -> *const c_char; + /// } + /// + /// unsafe { + /// let slice = CStr::from_ptr(my_string()); + /// println!("string returned: {}", slice.to_str().unwrap()); + /// } + /// # } + /// ``` + #[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)) + } + + /// Creates a C string wrapper from a byte slice. + /// + /// This function will cast the provided `bytes` to a `CStr` wrapper after + /// ensuring that it is null terminated and does not contain any interior + /// nul bytes. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::CStr; + /// + /// let cstr = CStr::from_bytes_with_nul(b"hello\0"); + /// assert!(cstr.is_ok()); + /// ``` + #[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) { + Err(FromBytesWithNulError { _a: () }) + } else { + Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) }) + } + } + + /// Unsafely creates a C string wrapper from a byte slice. + /// + /// This function will cast the provided `bytes` to a `CStr` wrapper without + /// performing any sanity checks. The provided slice must be null terminated + /// and not contain any interior nul bytes. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::{CStr, CString}; + /// + /// unsafe { + /// let cstring = CString::new("hello").unwrap(); + /// let cstr = CStr::from_bytes_with_nul_unchecked(cstring.to_bytes_with_nul()); + /// assert_eq!(cstr, &*cstring); + /// } + /// ``` + #[stable(feature = "cstr_from_bytes", since = "1.10.0")] + pub unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { + mem::transmute(bytes) + } + + /// Returns the inner pointer to this C string. + /// + /// The returned pointer will be valid for as long as `self` is and points + /// to a contiguous region of memory terminated with a 0 byte to represent + /// the end of the string. + /// + /// **WARNING** + /// + /// It is your responsibility to make sure that the underlying memory is not + /// freed too early. For example, the following code will cause undefined + /// behaviour when `ptr` is used inside the `unsafe` block: + /// + /// ```no_run + /// use std::ffi::{CString}; + /// + /// let ptr = CString::new("Hello").unwrap().as_ptr(); + /// unsafe { + /// // `ptr` is dangling + /// *ptr; + /// } + /// ``` + /// + /// This happens because the pointer returned by `as_ptr` does not carry any + /// lifetime information and the string is deallocated immediately after + /// the `CString::new("Hello").unwrap().as_ptr()` expression is evaluated. + /// To fix the problem, bind the string to a local variable: + /// + /// ```no_run + /// use std::ffi::{CString}; + /// + /// let hello = CString::new("Hello").unwrap(); + /// let ptr = hello.as_ptr(); + /// unsafe { + /// // `ptr` is valid because `hello` is in scope + /// *ptr; + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn as_ptr(&self) -> *const c_char { + self.inner.as_ptr() + } + + /// Converts this C string to a byte slice. + /// + /// This function will calculate the length of this string (which normally + /// requires a linear amount of work to be done) and then return the + /// resulting slice of `u8` elements. + /// + /// The returned slice will **not** contain the trailing nul that this C + /// string has. + /// + /// > **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] + } + + /// Converts this C string to a byte slice containing the trailing 0 byte. + /// + /// This function is the equivalent of `to_bytes` except that it will retain + /// the trailing nul instead of chopping it off. + /// + /// > **Note**: This method is currently implemented as a 0-cost cast, but + /// > it is planned to alter its definition in the future to perform the + /// > length calculation whenever this method is called. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn to_bytes_with_nul(&self) -> &[u8] { + unsafe { mem::transmute(&self.inner) } + } + + /// Yields a `&str` slice if the `CStr` contains valid UTF-8. + /// + /// This function will calculate the length of this string and check for + /// UTF-8 validity, and then return the `&str` if it's valid. + /// + /// > **Note**: This method is currently implemented to check for validity + /// > 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 + // be rewritten to do the UTF-8 check inline with the length calculation + // instead of doing it afterwards. + str::from_utf8(self.to_bytes()) + } + + /// Converts a `CStr` into a `Cow`. + /// + /// This function will calculate the length of this string (which normally + /// requires a linear amount of work to be done) and then return the + /// resulting slice as a `Cow`, replacing any invalid UTF-8 sequences + /// with `U+FFFD REPLACEMENT CHARACTER`. + /// + /// > **Note**: This method is currently implemented to check for validity + /// > 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; + + fn to_owned(&self) -> CString { + unsafe { CString::from_vec_unchecked(self.to_bytes().to_vec()) } + } +} + +#[stable(feature = "cstring_asref", since = "1.7.0")] +impl<'a> From<&'a CStr> for CString { + fn from(s: &'a CStr) -> CString { + s.to_owned() + } +} + +#[stable(feature = "cstring_asref", since = "1.7.0")] +impl ops::Index for CString { + type Output = CStr; + + #[inline] + fn index(&self, _index: ops::RangeFull) -> &CStr { + self + } +} + +#[stable(feature = "cstring_asref", since = "1.7.0")] +impl AsRef for CStr { + fn as_ref(&self) -> &CStr { + self + } +} + +#[stable(feature = "cstring_asref", since = "1.7.0")] +impl AsRef for CString { + fn as_ref(&self) -> &CStr { + self + } +} + +#[cfg(test)] +mod tests { + use super::*; + use os::raw::c_char; + use borrow::Cow::{Borrowed, Owned}; + use hash::{Hash, Hasher}; + use collections::hash_map::DefaultHasher; + + #[test] + fn c_to_rust() { + let data = b"123\0"; + let ptr = data.as_ptr() as *const c_char; + unsafe { + assert_eq!(CStr::from_ptr(ptr).to_bytes(), b"123"); + assert_eq!(CStr::from_ptr(ptr).to_bytes_with_nul(), b"123\0"); + } + } + + #[test] + fn simple() { + let s = CString::new("1234").unwrap(); + assert_eq!(s.as_bytes(), b"1234"); + assert_eq!(s.as_bytes_with_nul(), b"1234\0"); + } + + #[test] + fn build_with_zero1() { + assert!(CString::new(&b"\0"[..]).is_err()); + } + #[test] + fn build_with_zero2() { + assert!(CString::new(vec![0]).is_err()); + } + + #[test] + fn build_with_zero3() { + unsafe { + let s = CString::from_vec_unchecked(vec![0]); + assert_eq!(s.as_bytes(), b"\0"); + } + } + + #[test] + fn formatted() { + let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap(); + assert_eq!(format!("{:?}", s), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#); + } + + #[test] + fn borrowed() { + unsafe { + let s = CStr::from_ptr(b"12\0".as_ptr() as *const _); + assert_eq!(s.to_bytes(), b"12"); + assert_eq!(s.to_bytes_with_nul(), b"12\0"); + } + } + + #[test] + fn to_str() { + let data = b"123\xE2\x80\xA6\0"; + let ptr = data.as_ptr() as *const c_char; + unsafe { + assert_eq!(CStr::from_ptr(ptr).to_str(), Ok("123…")); + assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Borrowed("123…")); + } + let data = b"123\xE2\0"; + let ptr = data.as_ptr() as *const c_char; + unsafe { + assert!(CStr::from_ptr(ptr).to_str().is_err()); + assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Owned::(format!("123\u{FFFD}"))); + } + } + + #[test] + fn to_owned() { + let data = b"123\0"; + let ptr = data.as_ptr() as *const c_char; + + let owned = unsafe { CStr::from_ptr(ptr).to_owned() }; + assert_eq!(owned.as_bytes_with_nul(), data); + } + + #[test] + fn equal_hash() { + let data = b"123\xE2\xFA\xA6\0"; + let ptr = data.as_ptr() as *const c_char; + let cstr: &'static CStr = unsafe { CStr::from_ptr(ptr) }; + + let mut s = DefaultHasher::new(); + cstr.hash(&mut s); + let cstr_hash = s.finish(); + let mut s = DefaultHasher::new(); + CString::new(&data[..data.len() - 1]).unwrap().hash(&mut s); + let cstring_hash = s.finish(); + + assert_eq!(cstr_hash, cstring_hash); + } + + #[test] + fn from_bytes_with_nul() { + let data = b"123\0"; + let cstr = CStr::from_bytes_with_nul(data); + assert_eq!(cstr.map(CStr::to_bytes), Ok(&b"123"[..])); + let cstr = CStr::from_bytes_with_nul(data); + assert_eq!(cstr.map(CStr::to_bytes_with_nul), Ok(&b"123\0"[..])); + + unsafe { + let cstr = CStr::from_bytes_with_nul(data); + let cstr_unchecked = CStr::from_bytes_with_nul_unchecked(data); + assert_eq!(cstr, Ok(cstr_unchecked)); + } + } + + #[test] + fn from_bytes_with_nul_unterminated() { + let data = b"123"; + let cstr = CStr::from_bytes_with_nul(data); + assert!(cstr.is_err()); + } + + #[test] + fn from_bytes_with_nul_interior() { + let data = b"1\023\0"; + let cstr = CStr::from_bytes_with_nul(data); + assert!(cstr.is_err()); + } +} 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/src/ffi/os_str.rs b/ctr-std/src/ffi/os_str.rs similarity index 74% rename from src/ffi/os_str.rs rename to ctr-std/src/ffi/os_str.rs index d062d55..84b50f0 100644 --- a/src/ffi/os_str.rs +++ b/ctr-std/src/ffi/os_str.rs @@ -8,19 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use collections::borrow::{Borrow, Cow, ToOwned}; -use core::fmt::{self, Debug}; -use core::mem; -use collections::String; -use core::ops; -use core::cmp; -use core::hash::{Hash, Hasher}; -use collections::Vec; +use borrow::{Borrow, Cow}; +use fmt::{self, Debug}; +use mem; +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. @@ -39,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 } @@ -66,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. @@ -82,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() } @@ -96,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() } @@ -104,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) } @@ -115,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; @@ -152,6 +147,7 @@ impl ops::Index for OsString { } } +#[stable(feature = "rust1", since = "1.0.0")] impl ops::Deref for OsString { type Target = OsStr; @@ -161,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 { @@ -209,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 { @@ -216,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 { @@ -223,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) { @@ -232,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`. @@ -274,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. @@ -285,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 { @@ -340,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 { @@ -350,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()) } @@ -357,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 { @@ -374,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 { @@ -389,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) { @@ -396,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 } } @@ -456,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/ctr-std/src/io/buffered.rs b/ctr-std/src/io/buffered.rs new file mode 100644 index 0000000..44dd4e9 --- /dev/null +++ b/ctr-std/src/io/buffered.rs @@ -0,0 +1,1153 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Buffering wrappers for I/O traits + +use io::prelude::*; + +use cmp; +use error; +use fmt; +use io::{self, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom}; +use memchr; + +/// The `BufReader` struct adds buffering to any reader. +/// +/// It can be excessively inefficient to work directly with a [`Read`] instance. +/// For example, every call to [`read`] 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 +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io::BufReader; +/// use std::fs::File; +/// +/// # fn foo() -> std::io::Result<()> { +/// let mut f = try!(File::open("log.txt")); +/// let mut reader = BufReader::new(f); +/// +/// let mut line = String::new(); +/// let len = try!(reader.read_line(&mut line)); +/// println!("First line is {} bytes long", len); +/// # Ok(()) +/// # } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub struct BufReader { + inner: R, + buf: Box<[u8]>, + pos: usize, + cap: usize, +} + +impl BufReader { + /// Creates a new `BufReader` with a default buffer capacity. + /// + /// # Examples + /// + /// ``` + /// use std::io::BufReader; + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f = try!(File::open("log.txt")); + /// let mut reader = BufReader::new(f); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new(inner: R) -> BufReader { + BufReader::with_capacity(DEFAULT_BUF_SIZE, inner) + } + + /// Creates a new `BufReader` with the specified buffer capacity. + /// + /// # Examples + /// + /// Creating a buffer with ten bytes of capacity: + /// + /// ``` + /// use std::io::BufReader; + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f = try!(File::open("log.txt")); + /// let mut reader = BufReader::with_capacity(10, f); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn with_capacity(cap: usize, inner: R) -> BufReader { + BufReader { + inner: inner, + buf: vec![0; cap].into_boxed_slice(), + pos: 0, + cap: 0, + } + } + + /// Gets a reference to the underlying reader. + /// + /// It is inadvisable to directly read from the underlying reader. + /// + /// # Examples + /// + /// ``` + /// use std::io::BufReader; + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f1 = try!(File::open("log.txt")); + /// let mut reader = BufReader::new(f1); + /// + /// let f2 = reader.get_ref(); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_ref(&self) -> &R { &self.inner } + + /// Gets a mutable reference to the underlying reader. + /// + /// It is inadvisable to directly read from the underlying reader. + /// + /// # Examples + /// + /// ``` + /// use std::io::BufReader; + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f1 = try!(File::open("log.txt")); + /// let mut reader = BufReader::new(f1); + /// + /// let f2 = reader.get_mut(); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_mut(&mut self) -> &mut R { &mut self.inner } + + /// Unwraps this `BufReader`, returning the underlying reader. + /// + /// Note that any leftover data in the internal buffer is lost. + /// + /// # Examples + /// + /// ``` + /// use std::io::BufReader; + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f1 = try!(File::open("log.txt")); + /// let mut reader = BufReader::new(f1); + /// + /// let f2 = reader.into_inner(); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_inner(self) -> R { self.inner } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Read for BufReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + // If we don't have any buffered data and we're doing a massive read + // (larger than our internal buffer), bypass our internal buffer + // entirely. + if self.pos == self.cap && buf.len() >= self.buf.len() { + return self.inner.read(buf); + } + let nread = { + let mut rem = self.fill_buf()?; + rem.read(buf)? + }; + self.consume(nread); + Ok(nread) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl BufRead for BufReader { + fn fill_buf(&mut self) -> io::Result<&[u8]> { + // If we've reached the end of our internal buffer then we need to fetch + // some more data from the underlying reader. + if self.pos == self.cap { + self.cap = self.inner.read(&mut self.buf)?; + self.pos = 0; + } + Ok(&self.buf[self.pos..self.cap]) + } + + fn consume(&mut self, amt: usize) { + self.pos = cmp::min(self.pos + amt, self.cap); + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for BufReader where R: fmt::Debug { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("BufReader") + .field("reader", &self.inner) + .field("buffer", &format_args!("{}/{}", self.cap - self.pos, self.buf.len())) + .finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Seek for BufReader { + /// Seek to an offset, in bytes, in the underlying reader. + /// + /// The position used for seeking with `SeekFrom::Current(_)` is the + /// position the underlying reader would be at if the `BufReader` had no + /// internal buffer. + /// + /// Seeking always discards the internal buffer, even if the seek position + /// would otherwise fall within it. This guarantees that calling + /// `.into_inner()` immediately after a seek yields the underlying reader + /// at the same position. + /// + /// See `std::io::Seek` for more details. + /// + /// Note: In the edge case where you're seeking with `SeekFrom::Current(n)` + /// where `n` minus the internal buffer length underflows an `i64`, two + /// seeks will be performed instead of one. If the second seek returns + /// `Err`, the underlying reader will be left at the same position it would + /// have if you seeked to `SeekFrom::Current(0)`. + fn seek(&mut self, pos: SeekFrom) -> io::Result { + let result: u64; + if let SeekFrom::Current(n) = pos { + let remainder = (self.cap - self.pos) as i64; + // it should be safe to assume that remainder fits within an i64 as the alternative + // means we managed to allocate 8 exbibytes and that's absurd. + // But it's not out of the realm of possibility for some weird underlying reader to + // support seeking by i64::min_value() so we need to handle underflow when subtracting + // remainder. + if let Some(offset) = n.checked_sub(remainder) { + result = self.inner.seek(SeekFrom::Current(offset))?; + } else { + // seek backwards by our remainder, and then by the offset + self.inner.seek(SeekFrom::Current(-remainder))?; + self.pos = self.cap; // empty the buffer + result = self.inner.seek(SeekFrom::Current(n))?; + } + } else { + // Seeking with Start/End doesn't care about our buffer length. + result = self.inner.seek(pos)?; + } + self.pos = self.cap; // empty the buffer + Ok(result) + } +} + +/// Wraps a writer and buffers its output. +/// +/// It can be excessively inefficient to work directly with something that +/// implements [`Write`]. For example, every call to [`write`] 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. +/// +/// The buffer will be written out when the writer is dropped. +/// +/// # Examples +/// +/// Let's write the numbers one through ten to a [`TcpStream`]: +/// +/// ```no_run +/// use std::io::prelude::*; +/// use std::net::TcpStream; +/// +/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap(); +/// +/// for i in 1..10 { +/// stream.write(&[i]).unwrap(); +/// } +/// ``` +/// +/// Because we're not buffering, we write each one in turn, incurring the +/// overhead of a system call per byte written. We can fix this with a +/// `BufWriter`: +/// +/// ```no_run +/// use std::io::prelude::*; +/// use std::io::BufWriter; +/// use std::net::TcpStream; +/// +/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); +/// +/// for i in 1..10 { +/// stream.write(&[i]).unwrap(); +/// } +/// ``` +/// +/// By wrapping the stream with a `BufWriter`, these ten writes are all grouped +/// together by the buffer, and will all be written out in one system call when +/// the `stream` is dropped. +/// +/// [`Write`]: ../../std/io/trait.Write.html +/// [`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, + // #30888: If the inner writer panics in a call to write, we don't want to + // write the buffered data a second time in BufWriter's destructor. This + // flag tells the Drop impl if it should skip the flush. + panicked: bool, +} + +/// An error returned by `into_inner` which combines an error that +/// happened while writing out the buffer, and the buffered writer object +/// which may be used to recover from the condition. +/// +/// # Examples +/// +/// ```no_run +/// use std::io::BufWriter; +/// use std::net::TcpStream; +/// +/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); +/// +/// // do stuff with the stream +/// +/// // we want to get our `TcpStream` back, so let's try: +/// +/// let stream = match stream.into_inner() { +/// Ok(s) => s, +/// Err(e) => { +/// // Here, e is an IntoInnerError +/// panic!("An error occurred"); +/// } +/// }; +/// ``` +#[derive(Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct IntoInnerError(W, Error); + +impl BufWriter { + /// Creates a new `BufWriter` with a default buffer capacity. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new(inner: W) -> BufWriter { + BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner) + } + + /// Creates a new `BufWriter` with the specified buffer capacity. + /// + /// # Examples + /// + /// Creating a buffer with a buffer of a hundred bytes. + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:34254").unwrap(); + /// let mut buffer = BufWriter::with_capacity(100, stream); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn with_capacity(cap: usize, inner: W) -> BufWriter { + BufWriter { + inner: Some(inner), + buf: Vec::with_capacity(cap), + panicked: false, + } + } + + fn flush_buf(&mut self) -> io::Result<()> { + let mut written = 0; + let len = self.buf.len(); + let mut ret = Ok(()); + while written < len { + self.panicked = true; + let r = self.inner.as_mut().unwrap().write(&self.buf[written..]); + self.panicked = false; + + match r { + Ok(0) => { + ret = Err(Error::new(ErrorKind::WriteZero, + "failed to write the buffered data")); + break; + } + Ok(n) => written += n, + Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(e) => { ret = Err(e); break } + + } + } + if written > 0 { + self.buf.drain(..written); + } + ret + } + + /// Gets a reference to the underlying writer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // we can use reference just like buffer + /// let reference = buffer.get_ref(); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_ref(&self) -> &W { self.inner.as_ref().unwrap() } + + /// Gets a mutable reference to the underlying writer. + /// + /// It is inadvisable to directly write to the underlying writer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // we can use reference just like buffer + /// let reference = buffer.get_mut(); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_mut(&mut self) -> &mut W { self.inner.as_mut().unwrap() } + + /// Unwraps this `BufWriter`, returning the underlying writer. + /// + /// The buffer is written out before returning the writer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // unwrap the TcpStream and flush the buffer + /// let stream = buffer.into_inner().unwrap(); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_inner(mut self) -> Result>> { + match self.flush_buf() { + Err(e) => Err(IntoInnerError(self, e)), + Ok(()) => Ok(self.inner.take().unwrap()) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Write for BufWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + if self.buf.len() + buf.len() > self.buf.capacity() { + self.flush_buf()?; + } + if buf.len() >= self.buf.capacity() { + self.panicked = true; + let r = self.inner.as_mut().unwrap().write(buf); + self.panicked = false; + r + } else { + Write::write(&mut self.buf, buf) + } + } + fn flush(&mut self) -> io::Result<()> { + self.flush_buf().and_then(|()| self.get_mut().flush()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for BufWriter where W: fmt::Debug { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("BufWriter") + .field("writer", &self.inner.as_ref().unwrap()) + .field("buffer", &format_args!("{}/{}", self.buf.len(), self.buf.capacity())) + .finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Seek for BufWriter { + /// Seek to the offset, in bytes, in the underlying writer. + /// + /// Seeking always writes out the internal buffer before seeking. + fn seek(&mut self, pos: SeekFrom) -> io::Result { + self.flush_buf().and_then(|_| self.get_mut().seek(pos)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Drop for BufWriter { + fn drop(&mut self) { + if self.inner.is_some() && !self.panicked { + // dtors should not panic, so we ignore a failed flush + let _r = self.flush_buf(); + } + } +} + +impl IntoInnerError { + /// Returns the error which caused the call to `into_inner()` to fail. + /// + /// This error was returned when attempting to write the internal buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // do stuff with the stream + /// + /// // we want to get our `TcpStream` back, so let's try: + /// + /// let stream = match stream.into_inner() { + /// Ok(s) => s, + /// Err(e) => { + /// // Here, e is an IntoInnerError, let's log the inner error. + /// // + /// // We'll just 'log' to stdout for this example. + /// println!("{}", e.error()); + /// + /// panic!("An unexpected error occurred."); + /// } + /// }; + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn error(&self) -> &Error { &self.1 } + + /// Returns the buffered writer instance which generated the error. + /// + /// The returned object can be used for error recovery, such as + /// re-inspecting the buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // do stuff with the stream + /// + /// // we want to get our `TcpStream` back, so let's try: + /// + /// let stream = match stream.into_inner() { + /// Ok(s) => s, + /// Err(e) => { + /// // Here, e is an IntoInnerError, let's re-examine the buffer: + /// let buffer = e.into_inner(); + /// + /// // do stuff to try to recover + /// + /// // afterwards, let's just return the stream + /// buffer.into_inner().unwrap() + /// } + /// }; + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_inner(self) -> W { self.0 } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl From> for Error { + fn from(iie: IntoInnerError) -> Error { iie.1 } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl error::Error for IntoInnerError { + fn description(&self) -> &str { + error::Error::description(self.error()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for IntoInnerError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.error().fmt(f) + } +} + +/// Wraps a writer and buffers output to it, flushing whenever a newline +/// (`0x0a`, `'\n'`) is detected. +/// +/// The [`BufWriter`][bufwriter] struct wraps a writer and buffers its output. +/// But it only does this batched write when it goes out of scope, or when the +/// internal buffer is full. Sometimes, you'd prefer to write each line as it's +/// completed, rather than the entire buffer at once. Enter `LineWriter`. It +/// does exactly that. +/// +/// [bufwriter]: struct.BufWriter.html +/// +/// If there's still a partial line in the buffer when the `LineWriter` is +/// dropped, it will flush those contents. +/// +/// # Examples +/// +/// We can use `LineWriter` to write one line at a time, significantly +/// reducing the number of actual writes to the file. +/// +/// ``` +/// use std::fs::File; +/// use std::io::prelude::*; +/// use std::io::LineWriter; +/// +/// # fn foo() -> std::io::Result<()> { +/// let road_not_taken = b"I shall be telling this with a sigh +/// Somewhere ages and ages hence: +/// Two roads diverged in a wood, and I - +/// I took the one less traveled by, +/// And that has made all the difference."; +/// +/// let file = try!(File::create("poem.txt")); +/// let mut file = LineWriter::new(file); +/// +/// for &byte in road_not_taken.iter() { +/// file.write(&[byte]).unwrap(); +/// } +/// +/// // let's check we did the right thing. +/// let mut file = try!(File::open("poem.txt")); +/// let mut contents = String::new(); +/// +/// try!(file.read_to_string(&mut contents)); +/// +/// assert_eq!(contents.as_bytes(), &road_not_taken[..]); +/// # Ok(()) +/// # } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub struct LineWriter { + inner: BufWriter, +} + +impl LineWriter { + /// Creates a new `LineWriter`. + /// + /// # Examples + /// + /// ``` + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// # fn foo() -> std::io::Result<()> { + /// let file = try!(File::create("poem.txt")); + /// let file = LineWriter::new(file); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new(inner: W) -> LineWriter { + // Lines typically aren't that long, don't use a giant buffer + LineWriter::with_capacity(1024, inner) + } + + /// Creates a new `LineWriter` with a specified capacity for the internal + /// buffer. + /// + /// # Examples + /// + /// ``` + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// # fn foo() -> std::io::Result<()> { + /// let file = try!(File::create("poem.txt")); + /// let file = LineWriter::with_capacity(100, file); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn with_capacity(cap: usize, inner: W) -> LineWriter { + LineWriter { inner: BufWriter::with_capacity(cap, inner) } + } + + /// Gets a reference to the underlying writer. + /// + /// # Examples + /// + /// ``` + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// # fn foo() -> std::io::Result<()> { + /// let file = try!(File::create("poem.txt")); + /// let file = LineWriter::new(file); + /// + /// let reference = file.get_ref(); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_ref(&self) -> &W { self.inner.get_ref() } + + /// Gets a mutable reference to the underlying writer. + /// + /// Caution must be taken when calling methods on the mutable reference + /// returned as extra writes could corrupt the output stream. + /// + /// # Examples + /// + /// ``` + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// # fn foo() -> std::io::Result<()> { + /// let file = try!(File::create("poem.txt")); + /// let mut file = LineWriter::new(file); + /// + /// // we can use reference just like file + /// let reference = file.get_mut(); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_mut(&mut self) -> &mut W { self.inner.get_mut() } + + /// Unwraps this `LineWriter`, returning the underlying writer. + /// + /// The internal buffer is written out before returning the writer. + /// + /// # Examples + /// + /// ``` + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// # fn foo() -> std::io::Result<()> { + /// let file = try!(File::create("poem.txt")); + /// + /// let writer: LineWriter = LineWriter::new(file); + /// + /// let file: File = try!(writer.into_inner()); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_inner(self) -> Result>> { + self.inner.into_inner().map_err(|IntoInnerError(buf, e)| { + IntoInnerError(LineWriter { inner: buf }, e) + }) + } +} + +#[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) { + Some(i) => { + let n = self.inner.write(&buf[..i + 1])?; + if n != i + 1 || self.inner.flush().is_err() { + // Do not return errors on partial writes. + return Ok(n); + } + self.inner.write(&buf[i + 1..]).map(|i| n + i) + } + None => self.inner.write(buf), + } + } + + 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") + .field("writer", &self.inner.inner) + .field("buffer", + &format_args!("{}/{}", self.inner.buf.len(), self.inner.buf.capacity())) + .finish() + } +} + +#[cfg(test)] +mod tests { + use io::prelude::*; + use io::{self, BufReader, BufWriter, LineWriter, SeekFrom}; + use sync::atomic::{AtomicUsize, Ordering}; + use thread; + use test; + + /// A dummy reader intended at testing short-reads propagation. + pub struct ShortReader { + lengths: Vec, + } + + impl Read for ShortReader { + fn read(&mut self, _: &mut [u8]) -> io::Result { + if self.lengths.is_empty() { + Ok(0) + } else { + Ok(self.lengths.remove(0)) + } + } + } + + #[test] + fn test_buffered_reader() { + let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; + let mut reader = BufReader::with_capacity(2, inner); + + let mut buf = [0, 0, 0]; + let nread = reader.read(&mut buf); + assert_eq!(nread.unwrap(), 3); + let b: &[_] = &[5, 6, 7]; + assert_eq!(buf, b); + + let mut buf = [0, 0]; + let nread = reader.read(&mut buf); + assert_eq!(nread.unwrap(), 2); + let b: &[_] = &[0, 1]; + assert_eq!(buf, b); + + let mut buf = [0]; + let nread = reader.read(&mut buf); + assert_eq!(nread.unwrap(), 1); + let b: &[_] = &[2]; + assert_eq!(buf, b); + + let mut buf = [0, 0, 0]; + let nread = reader.read(&mut buf); + assert_eq!(nread.unwrap(), 1); + let b: &[_] = &[3, 0, 0]; + assert_eq!(buf, b); + + let nread = reader.read(&mut buf); + assert_eq!(nread.unwrap(), 1); + let b: &[_] = &[4, 0, 0]; + assert_eq!(buf, b); + + assert_eq!(reader.read(&mut buf).unwrap(), 0); + } + + #[test] + fn test_buffered_reader_seek() { + let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; + let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner)); + + assert_eq!(reader.seek(SeekFrom::Start(3)).ok(), Some(3)); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); + assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(3)); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); + assert_eq!(reader.seek(SeekFrom::Current(1)).ok(), Some(4)); + assert_eq!(reader.fill_buf().ok(), Some(&[1, 2][..])); + reader.consume(1); + assert_eq!(reader.seek(SeekFrom::Current(-2)).ok(), Some(3)); + } + + #[test] + fn test_buffered_reader_seek_underflow() { + // gimmick reader that yields its position modulo 256 for each byte + struct PositionReader { + pos: u64 + } + impl Read for PositionReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let len = buf.len(); + for x in buf { + *x = self.pos as u8; + self.pos = self.pos.wrapping_add(1); + } + Ok(len) + } + } + impl Seek for PositionReader { + fn seek(&mut self, pos: SeekFrom) -> io::Result { + match pos { + SeekFrom::Start(n) => { + self.pos = n; + } + SeekFrom::Current(n) => { + self.pos = self.pos.wrapping_add(n as u64); + } + SeekFrom::End(n) => { + self.pos = u64::max_value().wrapping_add(n as u64); + } + } + Ok(self.pos) + } + } + + let mut reader = BufReader::with_capacity(5, PositionReader { pos: 0 }); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1, 2, 3, 4][..])); + assert_eq!(reader.seek(SeekFrom::End(-5)).ok(), Some(u64::max_value()-5)); + assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5)); + // the following seek will require two underlying seeks + let expected = 9223372036854775802; + assert_eq!(reader.seek(SeekFrom::Current(i64::min_value())).ok(), Some(expected)); + assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5)); + // seeking to 0 should empty the buffer. + assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(expected)); + assert_eq!(reader.get_ref().pos, expected); + } + + #[test] + fn test_buffered_writer() { + let inner = Vec::new(); + let mut writer = BufWriter::with_capacity(2, inner); + + writer.write(&[0, 1]).unwrap(); + assert_eq!(*writer.get_ref(), [0, 1]); + + writer.write(&[2]).unwrap(); + assert_eq!(*writer.get_ref(), [0, 1]); + + writer.write(&[3]).unwrap(); + assert_eq!(*writer.get_ref(), [0, 1]); + + writer.flush().unwrap(); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); + + writer.write(&[4]).unwrap(); + writer.write(&[5]).unwrap(); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); + + writer.write(&[6]).unwrap(); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5]); + + writer.write(&[7, 8]).unwrap(); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]); + + writer.write(&[9, 10, 11]).unwrap(); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); + + writer.flush().unwrap(); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); + } + + #[test] + fn test_buffered_writer_inner_flushes() { + let mut w = BufWriter::with_capacity(3, Vec::new()); + w.write(&[0, 1]).unwrap(); + assert_eq!(*w.get_ref(), []); + let w = w.into_inner().unwrap(); + assert_eq!(w, [0, 1]); + } + + #[test] + fn test_buffered_writer_seek() { + let mut w = BufWriter::with_capacity(3, io::Cursor::new(Vec::new())); + w.write_all(&[0, 1, 2, 3, 4, 5]).unwrap(); + w.write_all(&[6, 7]).unwrap(); + assert_eq!(w.seek(SeekFrom::Current(0)).ok(), Some(8)); + assert_eq!(&w.get_ref().get_ref()[..], &[0, 1, 2, 3, 4, 5, 6, 7][..]); + assert_eq!(w.seek(SeekFrom::Start(2)).ok(), Some(2)); + w.write_all(&[8, 9]).unwrap(); + assert_eq!(&w.into_inner().unwrap().into_inner()[..], &[0, 1, 8, 9, 4, 5, 6, 7]); + } + + #[test] + fn test_read_until() { + let inner: &[u8] = &[0, 1, 2, 1, 0]; + let mut reader = BufReader::with_capacity(2, inner); + let mut v = Vec::new(); + reader.read_until(0, &mut v).unwrap(); + assert_eq!(v, [0]); + v.truncate(0); + reader.read_until(2, &mut v).unwrap(); + assert_eq!(v, [1, 2]); + v.truncate(0); + reader.read_until(1, &mut v).unwrap(); + assert_eq!(v, [1]); + v.truncate(0); + reader.read_until(8, &mut v).unwrap(); + assert_eq!(v, [0]); + v.truncate(0); + reader.read_until(9, &mut v).unwrap(); + assert_eq!(v, []); + } + + #[test] + fn test_line_buffer_fail_flush() { + // Issue #32085 + struct FailFlushWriter<'a>(&'a mut Vec); + + impl<'a> Write for FailFlushWriter<'a> { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.extend_from_slice(buf); + Ok(buf.len()) + } + fn flush(&mut self) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::Other, "flush failed")) + } + } + + let mut buf = Vec::new(); + { + let mut writer = LineWriter::new(FailFlushWriter(&mut buf)); + let to_write = b"abc\ndef"; + if let Ok(written) = writer.write(to_write) { + assert!(written < to_write.len(), "didn't flush on new line"); + // PASS + return; + } + } + assert!(buf.is_empty(), "write returned an error but wrote data"); + } + + #[test] + fn test_line_buffer() { + let mut writer = LineWriter::new(Vec::new()); + writer.write(&[0]).unwrap(); + assert_eq!(*writer.get_ref(), []); + writer.write(&[1]).unwrap(); + assert_eq!(*writer.get_ref(), []); + writer.flush().unwrap(); + assert_eq!(*writer.get_ref(), [0, 1]); + writer.write(&[0, b'\n', 1, b'\n', 2]).unwrap(); + assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n']); + writer.flush().unwrap(); + assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2]); + writer.write(&[3, b'\n']).unwrap(); + assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2, 3, b'\n']); + } + + #[test] + fn test_read_line() { + let in_buf: &[u8] = b"a\nb\nc"; + let mut reader = BufReader::with_capacity(2, in_buf); + let mut s = String::new(); + reader.read_line(&mut s).unwrap(); + assert_eq!(s, "a\n"); + s.truncate(0); + reader.read_line(&mut s).unwrap(); + assert_eq!(s, "b\n"); + s.truncate(0); + reader.read_line(&mut s).unwrap(); + assert_eq!(s, "c"); + s.truncate(0); + reader.read_line(&mut s).unwrap(); + assert_eq!(s, ""); + } + + #[test] + fn test_lines() { + let in_buf: &[u8] = b"a\nb\nc"; + let reader = BufReader::with_capacity(2, in_buf); + let mut it = reader.lines(); + assert_eq!(it.next().unwrap().unwrap(), "a".to_string()); + assert_eq!(it.next().unwrap().unwrap(), "b".to_string()); + assert_eq!(it.next().unwrap().unwrap(), "c".to_string()); + assert!(it.next().is_none()); + } + + #[test] + fn test_short_reads() { + let inner = ShortReader{lengths: vec![0, 1, 2, 0, 1, 0]}; + let mut reader = BufReader::new(inner); + let mut buf = [0, 0]; + assert_eq!(reader.read(&mut buf).unwrap(), 0); + assert_eq!(reader.read(&mut buf).unwrap(), 1); + assert_eq!(reader.read(&mut buf).unwrap(), 2); + assert_eq!(reader.read(&mut buf).unwrap(), 0); + assert_eq!(reader.read(&mut buf).unwrap(), 1); + assert_eq!(reader.read(&mut buf).unwrap(), 0); + assert_eq!(reader.read(&mut buf).unwrap(), 0); + } + + #[test] + fn read_char_buffered() { + let buf = [195, 159]; + let reader = BufReader::with_capacity(1, &buf[..]); + assert_eq!(reader.chars().next().unwrap().unwrap(), 'ß'); + } + + #[test] + fn test_chars() { + let buf = [195, 159, b'a']; + let reader = BufReader::with_capacity(1, &buf[..]); + let mut it = reader.chars(); + assert_eq!(it.next().unwrap().unwrap(), 'ß'); + assert_eq!(it.next().unwrap().unwrap(), 'a'); + assert!(it.next().is_none()); + } + + #[test] + #[should_panic] + fn dont_panic_in_drop_on_panicked_flush() { + struct FailFlushWriter; + + impl Write for FailFlushWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { Ok(buf.len()) } + fn flush(&mut self) -> io::Result<()> { + Err(io::Error::last_os_error()) + } + } + + let writer = FailFlushWriter; + let _writer = BufWriter::new(writer); + + // If writer panics *again* due to the flush error then the process will + // abort. + panic!(); + } + + #[test] + #[cfg_attr(target_os = "emscripten", ignore)] + fn panic_in_write_doesnt_flush_in_drop() { + static WRITES: AtomicUsize = AtomicUsize::new(0); + + struct PanicWriter; + + impl Write for PanicWriter { + fn write(&mut self, _: &[u8]) -> io::Result { + WRITES.fetch_add(1, Ordering::SeqCst); + panic!(); + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } + } + + thread::spawn(|| { + let mut writer = BufWriter::new(PanicWriter); + let _ = writer.write(b"hello world"); + let _ = writer.flush(); + }).join().unwrap_err(); + + assert_eq!(WRITES.load(Ordering::SeqCst), 1); + } + + #[bench] + fn bench_buffered_reader(b: &mut test::Bencher) { + b.iter(|| { + BufReader::new(io::empty()) + }); + } + + #[bench] + fn bench_buffered_writer(b: &mut test::Bencher) { + b.iter(|| { + BufWriter::new(io::sink()) + }); + } +} diff --git a/ctr-std/src/io/cursor.rs b/ctr-std/src/io/cursor.rs new file mode 100644 index 0000000..1b50233 --- /dev/null +++ b/ctr-std/src/io/cursor.rs @@ -0,0 +1,600 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use io::prelude::*; + +use core::convert::TryInto; +use cmp; +use io::{self, SeekFrom, Error, ErrorKind}; + +/// A `Cursor` wraps another type and provides it with a +/// [`Seek`] implementation. +/// +/// `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<`[`Vec`]`>` and +/// `Cursor<`[`&[u8]`][bytes]`>`. +/// +/// # Examples +/// +/// We may want to write bytes to a [`File`] in our production +/// code, but use an in-memory buffer in our tests. We can do this with +/// `Cursor`: +/// +/// [`Seek`]: trait.Seek.html +/// [`Read`]: ../../std/io/trait.Read.html +/// [`Write`]: ../../std/io/trait.Write.html +/// [`Vec`]: ../../std/vec/struct.Vec.html +/// [bytes]: ../../std/primitive.slice.html +/// [`File`]: ../fs/struct.File.html +/// +/// ```no_run +/// use std::io::prelude::*; +/// use std::io::{self, SeekFrom}; +/// use std::fs::File; +/// +/// // a library function we've written +/// fn write_ten_bytes_at_end(writer: &mut W) -> io::Result<()> { +/// try!(writer.seek(SeekFrom::End(-10))); +/// +/// for i in 0..10 { +/// try!(writer.write(&[i])); +/// } +/// +/// // all went well +/// Ok(()) +/// } +/// +/// # fn foo() -> io::Result<()> { +/// // Here's some code that uses this library function. +/// // +/// // We might want to use a BufReader here for efficiency, but let's +/// // keep this example focused. +/// let mut file = try!(File::create("foo.txt")); +/// +/// try!(write_ten_bytes_at_end(&mut file)); +/// # Ok(()) +/// # } +/// +/// // now let's write a test +/// #[test] +/// fn test_writes_bytes() { +/// // setting up a real File is much more slow than an in-memory buffer, +/// // let's use a cursor instead +/// use std::io::Cursor; +/// let mut buff = Cursor::new(vec![0; 15]); +/// +/// write_ten_bytes_at_end(&mut buff).unwrap(); +/// +/// assert_eq!(&buff.get_ref()[5..15], &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); +/// } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone, Debug)] +pub struct Cursor { + inner: T, + pos: u64, +} + +impl Cursor { + /// Creates a new cursor wrapping the provided underlying I/O object. + /// + /// # Examples + /// + /// ``` + /// use std::io::Cursor; + /// + /// let buff = Cursor::new(Vec::new()); + /// # fn force_inference(_: &Cursor>) {} + /// # force_inference(&buff); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new(inner: T) -> Cursor { + Cursor { pos: 0, inner: inner } + } + + /// Consumes this cursor, returning the underlying value. + /// + /// # Examples + /// + /// ``` + /// use std::io::Cursor; + /// + /// let buff = Cursor::new(Vec::new()); + /// # fn force_inference(_: &Cursor>) {} + /// # force_inference(&buff); + /// + /// let vec = buff.into_inner(); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_inner(self) -> T { self.inner } + + /// Gets a reference to the underlying value in this cursor. + /// + /// # Examples + /// + /// ``` + /// use std::io::Cursor; + /// + /// let buff = Cursor::new(Vec::new()); + /// # fn force_inference(_: &Cursor>) {} + /// # force_inference(&buff); + /// + /// let reference = buff.get_ref(); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_ref(&self) -> &T { &self.inner } + + /// Gets a mutable reference to the underlying value in this cursor. + /// + /// Care should be taken to avoid modifying the internal I/O state of the + /// underlying value as it may corrupt this cursor's position. + /// + /// # Examples + /// + /// ``` + /// use std::io::Cursor; + /// + /// let mut buff = Cursor::new(Vec::new()); + /// # fn force_inference(_: &Cursor>) {} + /// # force_inference(&buff); + /// + /// let reference = buff.get_mut(); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_mut(&mut self) -> &mut T { &mut self.inner } + + /// Returns the current position of this cursor. + /// + /// # Examples + /// + /// ``` + /// use std::io::Cursor; + /// use std::io::prelude::*; + /// use std::io::SeekFrom; + /// + /// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]); + /// + /// assert_eq!(buff.position(), 0); + /// + /// buff.seek(SeekFrom::Current(2)).unwrap(); + /// assert_eq!(buff.position(), 2); + /// + /// buff.seek(SeekFrom::Current(-1)).unwrap(); + /// assert_eq!(buff.position(), 1); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn position(&self) -> u64 { self.pos } + + /// Sets the position of this cursor. + /// + /// # Examples + /// + /// ``` + /// use std::io::Cursor; + /// + /// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]); + /// + /// assert_eq!(buff.position(), 0); + /// + /// buff.set_position(2); + /// assert_eq!(buff.position(), 2); + /// + /// buff.set_position(4); + /// assert_eq!(buff.position(), 4); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn set_position(&mut self, pos: u64) { self.pos = pos; } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl io::Seek for Cursor where T: AsRef<[u8]> { + fn seek(&mut self, style: SeekFrom) -> io::Result { + let pos = match style { + SeekFrom::Start(n) => { self.pos = n; return Ok(n) } + SeekFrom::End(n) => self.inner.as_ref().len() as i64 + n, + SeekFrom::Current(n) => self.pos as i64 + n, + }; + + if pos < 0 { + Err(Error::new(ErrorKind::InvalidInput, + "invalid seek to a negative position")) + } else { + self.pos = pos as u64; + Ok(self.pos) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Read for Cursor where T: AsRef<[u8]> { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let n = Read::read(&mut self.fill_buf()?, buf)?; + self.pos += n as u64; + Ok(n) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl BufRead for Cursor where T: AsRef<[u8]> { + fn fill_buf(&mut self) -> io::Result<&[u8]> { + let amt = cmp::min(self.pos, self.inner.as_ref().len() as u64); + Ok(&self.inner.as_ref()[(amt as usize)..]) + } + fn consume(&mut self, amt: usize) { self.pos += amt as u64; } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> Write for Cursor<&'a mut [u8]> { + #[inline] + fn write(&mut self, data: &[u8]) -> io::Result { + let pos = cmp::min(self.pos, self.inner.len() as u64); + let amt = (&mut self.inner[(pos as usize)..]).write(data)?; + self.pos += amt as u64; + Ok(amt) + } + 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 len = self.inner.len(); + 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 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); + self.inner.extend_from_slice(right); + } + + // Bump us forward + 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 { + let pos = cmp::min(self.pos, self.inner.len() as u64); + let amt = (&mut self.inner[(pos as usize)..]).write(buf)?; + self.pos += amt as u64; + Ok(amt) + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } +} + +#[cfg(test)] +mod tests { + use io::prelude::*; + use io::{Cursor, SeekFrom}; + + #[test] + fn test_vec_writer() { + let mut writer = Vec::new(); + assert_eq!(writer.write(&[0]).unwrap(), 1); + assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); + assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; + assert_eq!(writer, b); + } + + #[test] + fn test_mem_writer() { + let mut writer = Cursor::new(Vec::new()); + assert_eq!(writer.write(&[0]).unwrap(), 1); + assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); + assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; + assert_eq!(&writer.get_ref()[..], b); + } + + #[test] + fn test_box_slice_writer() { + let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice()); + assert_eq!(writer.position(), 0); + assert_eq!(writer.write(&[0]).unwrap(), 1); + assert_eq!(writer.position(), 1); + assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); + assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); + assert_eq!(writer.position(), 8); + assert_eq!(writer.write(&[]).unwrap(), 0); + assert_eq!(writer.position(), 8); + + assert_eq!(writer.write(&[8, 9]).unwrap(), 1); + assert_eq!(writer.write(&[10]).unwrap(), 0); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; + assert_eq!(&**writer.get_ref(), b); + } + + #[test] + fn test_buf_writer() { + let mut buf = [0 as u8; 9]; + { + let mut writer = Cursor::new(&mut buf[..]); + assert_eq!(writer.position(), 0); + assert_eq!(writer.write(&[0]).unwrap(), 1); + assert_eq!(writer.position(), 1); + assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); + assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); + assert_eq!(writer.position(), 8); + assert_eq!(writer.write(&[]).unwrap(), 0); + assert_eq!(writer.position(), 8); + + assert_eq!(writer.write(&[8, 9]).unwrap(), 1); + assert_eq!(writer.write(&[10]).unwrap(), 0); + } + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; + assert_eq!(buf, b); + } + + #[test] + fn test_buf_writer_seek() { + let mut buf = [0 as u8; 8]; + { + let mut writer = Cursor::new(&mut buf[..]); + assert_eq!(writer.position(), 0); + assert_eq!(writer.write(&[1]).unwrap(), 1); + assert_eq!(writer.position(), 1); + + assert_eq!(writer.seek(SeekFrom::Start(2)).unwrap(), 2); + assert_eq!(writer.position(), 2); + assert_eq!(writer.write(&[2]).unwrap(), 1); + assert_eq!(writer.position(), 3); + + assert_eq!(writer.seek(SeekFrom::Current(-2)).unwrap(), 1); + assert_eq!(writer.position(), 1); + assert_eq!(writer.write(&[3]).unwrap(), 1); + assert_eq!(writer.position(), 2); + + assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7); + assert_eq!(writer.position(), 7); + assert_eq!(writer.write(&[4]).unwrap(), 1); + assert_eq!(writer.position(), 8); + + } + let b: &[_] = &[1, 3, 2, 0, 0, 0, 0, 4]; + assert_eq!(buf, b); + } + + #[test] + fn test_buf_writer_error() { + let mut buf = [0 as u8; 2]; + let mut writer = Cursor::new(&mut buf[..]); + assert_eq!(writer.write(&[0]).unwrap(), 1); + assert_eq!(writer.write(&[0, 0]).unwrap(), 1); + assert_eq!(writer.write(&[0, 0]).unwrap(), 0); + } + + #[test] + fn test_mem_reader() { + let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]); + let mut buf = []; + assert_eq!(reader.read(&mut buf).unwrap(), 0); + assert_eq!(reader.position(), 0); + let mut buf = [0]; + assert_eq!(reader.read(&mut buf).unwrap(), 1); + assert_eq!(reader.position(), 1); + let b: &[_] = &[0]; + assert_eq!(buf, b); + let mut buf = [0; 4]; + assert_eq!(reader.read(&mut buf).unwrap(), 4); + assert_eq!(reader.position(), 5); + let b: &[_] = &[1, 2, 3, 4]; + assert_eq!(buf, b); + assert_eq!(reader.read(&mut buf).unwrap(), 3); + let b: &[_] = &[5, 6, 7]; + assert_eq!(&buf[..3], b); + assert_eq!(reader.read(&mut buf).unwrap(), 0); + } + + #[test] + fn test_boxed_slice_reader() { + let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice()); + let mut buf = []; + assert_eq!(reader.read(&mut buf).unwrap(), 0); + assert_eq!(reader.position(), 0); + let mut buf = [0]; + assert_eq!(reader.read(&mut buf).unwrap(), 1); + assert_eq!(reader.position(), 1); + let b: &[_] = &[0]; + assert_eq!(buf, b); + let mut buf = [0; 4]; + assert_eq!(reader.read(&mut buf).unwrap(), 4); + assert_eq!(reader.position(), 5); + let b: &[_] = &[1, 2, 3, 4]; + assert_eq!(buf, b); + assert_eq!(reader.read(&mut buf).unwrap(), 3); + let b: &[_] = &[5, 6, 7]; + assert_eq!(&buf[..3], b); + assert_eq!(reader.read(&mut buf).unwrap(), 0); + } + + #[test] + fn read_to_end() { + let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]); + let mut v = Vec::new(); + reader.read_to_end(&mut v).unwrap(); + assert_eq!(v, [0, 1, 2, 3, 4, 5, 6, 7]); + } + + #[test] + fn test_slice_reader() { + let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; + let mut reader = &mut &in_buf[..]; + let mut buf = []; + assert_eq!(reader.read(&mut buf).unwrap(), 0); + let mut buf = [0]; + assert_eq!(reader.read(&mut buf).unwrap(), 1); + assert_eq!(reader.len(), 7); + let b: &[_] = &[0]; + assert_eq!(&buf[..], b); + let mut buf = [0; 4]; + assert_eq!(reader.read(&mut buf).unwrap(), 4); + assert_eq!(reader.len(), 3); + let b: &[_] = &[1, 2, 3, 4]; + assert_eq!(&buf[..], b); + assert_eq!(reader.read(&mut buf).unwrap(), 3); + let b: &[_] = &[5, 6, 7]; + assert_eq!(&buf[..3], b); + assert_eq!(reader.read(&mut buf).unwrap(), 0); + } + + #[test] + fn test_buf_reader() { + let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; + let mut reader = Cursor::new(&in_buf[..]); + let mut buf = []; + assert_eq!(reader.read(&mut buf).unwrap(), 0); + assert_eq!(reader.position(), 0); + let mut buf = [0]; + assert_eq!(reader.read(&mut buf).unwrap(), 1); + assert_eq!(reader.position(), 1); + let b: &[_] = &[0]; + assert_eq!(buf, b); + let mut buf = [0; 4]; + assert_eq!(reader.read(&mut buf).unwrap(), 4); + assert_eq!(reader.position(), 5); + let b: &[_] = &[1, 2, 3, 4]; + assert_eq!(buf, b); + assert_eq!(reader.read(&mut buf).unwrap(), 3); + let b: &[_] = &[5, 6, 7]; + assert_eq!(&buf[..3], b); + assert_eq!(reader.read(&mut buf).unwrap(), 0); + } + + #[test] + fn test_read_char() { + let b = &b"Vi\xE1\xBB\x87t"[..]; + let mut c = Cursor::new(b).chars(); + assert_eq!(c.next().unwrap().unwrap(), 'V'); + assert_eq!(c.next().unwrap().unwrap(), 'i'); + assert_eq!(c.next().unwrap().unwrap(), 'ệ'); + assert_eq!(c.next().unwrap().unwrap(), 't'); + assert!(c.next().is_none()); + } + + #[test] + fn test_read_bad_char() { + let b = &b"\x80"[..]; + let mut c = Cursor::new(b).chars(); + assert!(c.next().unwrap().is_err()); + } + + #[test] + fn seek_past_end() { + let buf = [0xff]; + let mut r = Cursor::new(&buf[..]); + assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); + assert_eq!(r.read(&mut [0]).unwrap(), 0); + + let mut r = Cursor::new(vec![10]); + assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); + assert_eq!(r.read(&mut [0]).unwrap(), 0); + + let mut buf = [0]; + let mut r = Cursor::new(&mut buf[..]); + assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); + assert_eq!(r.write(&[3]).unwrap(), 0); + + let mut r = Cursor::new(vec![10].into_boxed_slice()); + assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); + assert_eq!(r.write(&[3]).unwrap(), 0); + } + + #[test] + fn seek_before_0() { + let buf = [0xff]; + let mut r = Cursor::new(&buf[..]); + assert!(r.seek(SeekFrom::End(-2)).is_err()); + + let mut r = Cursor::new(vec![10]); + assert!(r.seek(SeekFrom::End(-2)).is_err()); + + let mut buf = [0]; + let mut r = Cursor::new(&mut buf[..]); + assert!(r.seek(SeekFrom::End(-2)).is_err()); + + let mut r = Cursor::new(vec![10].into_boxed_slice()); + assert!(r.seek(SeekFrom::End(-2)).is_err()); + } + + #[test] + fn test_seekable_mem_writer() { + let mut writer = Cursor::new(Vec::::new()); + assert_eq!(writer.position(), 0); + assert_eq!(writer.write(&[0]).unwrap(), 1); + assert_eq!(writer.position(), 1); + assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); + assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); + assert_eq!(writer.position(), 8); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; + assert_eq!(&writer.get_ref()[..], b); + + assert_eq!(writer.seek(SeekFrom::Start(0)).unwrap(), 0); + assert_eq!(writer.position(), 0); + assert_eq!(writer.write(&[3, 4]).unwrap(), 2); + let b: &[_] = &[3, 4, 2, 3, 4, 5, 6, 7]; + assert_eq!(&writer.get_ref()[..], b); + + assert_eq!(writer.seek(SeekFrom::Current(1)).unwrap(), 3); + assert_eq!(writer.write(&[0, 1]).unwrap(), 2); + let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 7]; + assert_eq!(&writer.get_ref()[..], b); + + assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7); + assert_eq!(writer.write(&[1, 2]).unwrap(), 2); + let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2]; + assert_eq!(&writer.get_ref()[..], b); + + assert_eq!(writer.seek(SeekFrom::End(1)).unwrap(), 10); + assert_eq!(writer.write(&[1]).unwrap(), 1); + let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1]; + assert_eq!(&writer.get_ref()[..], b); + } + + #[test] + fn vec_seek_past_end() { + let mut r = Cursor::new(Vec::new()); + assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); + assert_eq!(r.write(&[3]).unwrap(), 1); + } + + #[test] + fn vec_seek_before_0() { + let mut r = Cursor::new(Vec::new()); + assert!(r.seek(SeekFrom::End(-2)).is_err()); + } + + #[test] + #[cfg(target_pointer_width = "32")] + fn vec_seek_and_write_past_usize_max() { + let mut c = Cursor::new(Vec::new()); + c.set_position(::max_value() as u64 + 1); + assert!(c.write_all(&[1, 2, 3]).is_err()); + } +} diff --git a/ctr-std/src/io/error.rs b/ctr-std/src/io/error.rs new file mode 100644 index 0000000..795c89c --- /dev/null +++ b/ctr-std/src/io/error.rs @@ -0,0 +1,594 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use error; +use fmt; +use result; +use sys; +use convert::From; + +/// A specialized [`Result`](../result/enum.Result.html) type for I/O +/// operations. +/// +/// This type is broadly used across `std::io` for any operation which may +/// produce an error. +/// +/// This typedef is generally used to avoid writing out `io::Error` directly and +/// is otherwise a direct mapping to `Result`. +/// +/// While usual Rust style is to import types directly, aliases of `Result` +/// often are not, to make it easier to distinguish between them. `Result` is +/// generally assumed to be `std::result::Result`, and so users of this alias +/// will generally use `io::Result` instead of shadowing the prelude's import +/// of `std::result::Result`. +/// +/// # Examples +/// +/// A convenience function that bubbles an `io::Result` to its caller: +/// +/// ``` +/// use std::io; +/// +/// fn get_string() -> io::Result { +/// let mut buffer = String::new(); +/// +/// try!(io::stdin().read_line(&mut buffer)); +/// +/// Ok(buffer) +/// } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub type Result = result::Result; + +/// The error type for I/O operations of the `Read`, `Write`, `Seek`, and +/// associated traits. +/// +/// Errors mostly originate from the underlying OS, but custom instances of +/// `Error` can be created with crafted error messages and a particular value of +/// [`ErrorKind`]. +/// +/// [`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), +} + +#[derive(Debug)] +struct Custom { + kind: ErrorKind, + error: Box, +} + +/// A list specifying general categories of I/O error. +/// +/// This list is intended to grow over time and it is not recommended to +/// exhaustively match against it. +/// +/// It is used with the [`io::Error`] type. +/// +/// [`io::Error`]: struct.Error.html +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] +pub enum ErrorKind { + /// An entity was not found, often a file. + #[stable(feature = "rust1", since = "1.0.0")] + NotFound, + /// The operation lacked the necessary privileges to complete. + #[stable(feature = "rust1", since = "1.0.0")] + PermissionDenied, + /// The connection was refused by the remote server. + #[stable(feature = "rust1", since = "1.0.0")] + ConnectionRefused, + /// The connection was reset by the remote server. + #[stable(feature = "rust1", since = "1.0.0")] + ConnectionReset, + /// The connection was aborted (terminated) by the remote server. + #[stable(feature = "rust1", since = "1.0.0")] + ConnectionAborted, + /// The network operation failed because it was not connected yet. + #[stable(feature = "rust1", since = "1.0.0")] + NotConnected, + /// A socket address could not be bound because the address is already in + /// use elsewhere. + #[stable(feature = "rust1", since = "1.0.0")] + AddrInUse, + /// A nonexistent interface was requested or the requested address was not + /// local. + #[stable(feature = "rust1", since = "1.0.0")] + AddrNotAvailable, + /// The operation failed because a pipe was closed. + #[stable(feature = "rust1", since = "1.0.0")] + BrokenPipe, + /// An entity already exists, often a file. + #[stable(feature = "rust1", since = "1.0.0")] + AlreadyExists, + /// The operation needs to block to complete, but the blocking operation was + /// requested to not occur. + #[stable(feature = "rust1", since = "1.0.0")] + WouldBlock, + /// A parameter was incorrect. + #[stable(feature = "rust1", since = "1.0.0")] + InvalidInput, + /// Data not valid for the operation were encountered. + /// + /// Unlike [`InvalidInput`], this typically means that the operation + /// parameters were valid, however the error was caused by malformed + /// input data. + /// + /// For example, a function that reads a file into a string will error with + /// `InvalidData` if the file's contents are not valid UTF-8. + /// + /// [`InvalidInput`]: #variant.InvalidInput + #[stable(feature = "io_invalid_data", since = "1.2.0")] + InvalidData, + /// The I/O operation's timeout expired, causing it to be canceled. + #[stable(feature = "rust1", since = "1.0.0")] + TimedOut, + /// An error returned when an operation could not be completed because a + /// call to [`write()`] returned [`Ok(0)`]. + /// + /// This typically means that an operation could only succeed if it wrote a + /// particular number of bytes but only a smaller number of bytes could be + /// written. + /// + /// [`write()`]: ../../std/io/trait.Write.html#tymethod.write + /// [`Ok(0)`]: ../../std/io/type.Result.html + #[stable(feature = "rust1", since = "1.0.0")] + WriteZero, + /// This operation was interrupted. + /// + /// Interrupted operations can typically be retried. + #[stable(feature = "rust1", since = "1.0.0")] + Interrupted, + /// Any I/O error not part of this list. + #[stable(feature = "rust1", since = "1.0.0")] + Other, + + /// An error returned when an operation could not be completed because an + /// "end of file" was reached prematurely. + /// + /// This typically means that an operation could only succeed if it read a + /// particular number of bytes but only a smaller number of bytes could be + /// read. + #[stable(feature = "read_exact", since = "1.6.0")] + UnexpectedEof, + + /// 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. + /// + /// This function is used to generically create I/O errors which do not + /// originate from the OS itself. The `error` argument is an arbitrary + /// payload which will be contained in this `Error`. + /// + /// # Examples + /// + /// ``` + /// use std::io::{Error, ErrorKind}; + /// + /// // errors can be created from strings + /// let custom_error = Error::new(ErrorKind::Other, "oh no!"); + /// + /// // errors can also be created from other errors + /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new(kind: ErrorKind, error: E) -> Error + where E: Into> + { + Self::_new(kind, error.into()) + } + + fn _new(kind: ErrorKind, error: Box) -> Error { + Error { + repr: Repr::Custom(Box::new(Custom { + kind: kind, + error: 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) } + } + + /// Returns the OS error that this error represents (if any). + /// + /// If this `Error` was constructed via `last_os_error` or + /// `from_raw_os_error`, then this function will return `Some`, otherwise + /// it will return `None`. + /// + /// # Examples + /// + /// ``` + /// use std::io::{Error, ErrorKind}; + /// + /// fn print_os_error(err: &Error) { + /// if let Some(raw_os_err) = err.raw_os_error() { + /// println!("raw OS error: {:?}", raw_os_err); + /// } else { + /// println!("Not an OS error"); + /// } + /// } + /// + /// fn main() { + /// // Will print "raw OS error: ...". + /// print_os_error(&Error::last_os_error()); + /// // Will print "Not an OS error". + /// print_os_error(&Error::new(ErrorKind::Other, "oh no!")); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn raw_os_error(&self) -> Option { + match self.repr { + Repr::Os(i) => Some(i), + Repr::Custom(..) => None, + Repr::Simple(..) => None, + } + } + + /// Returns a reference to the inner error wrapped by this error (if any). + /// + /// If this `Error` was constructed via `new` then this function will + /// return `Some`, otherwise it will return `None`. + /// + /// # Examples + /// + /// ``` + /// use std::io::{Error, ErrorKind}; + /// + /// fn print_error(err: &Error) { + /// if let Some(inner_err) = err.get_ref() { + /// println!("Inner error: {:?}", inner_err); + /// } else { + /// println!("No inner error"); + /// } + /// } + /// + /// fn main() { + /// // Will print "No inner error". + /// print_error(&Error::last_os_error()); + /// // Will print "Inner error: ...". + /// print_error(&Error::new(ErrorKind::Other, "oh no!")); + /// } + /// ``` + #[stable(feature = "io_error_inner", since = "1.3.0")] + pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync+'static)> { + match self.repr { + Repr::Os(..) => None, + Repr::Simple(..) => None, + Repr::Custom(ref c) => Some(&*c.error), + } + } + + /// Returns a mutable reference to the inner error wrapped by this error + /// (if any). + /// + /// If this `Error` was constructed via `new` then this function will + /// return `Some`, otherwise it will return `None`. + /// + /// # Examples + /// + /// ``` + /// use std::io::{Error, ErrorKind}; + /// use std::{error, fmt}; + /// use std::fmt::Display; + /// + /// #[derive(Debug)] + /// struct MyError { + /// v: String, + /// } + /// + /// impl MyError { + /// fn new() -> MyError { + /// MyError { + /// v: "oh no!".to_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), + } + } + + /// Consumes the `Error`, returning its inner error (if any). + /// + /// If this `Error` was constructed via `new` then this function will + /// return `Some`, otherwise it will return `None`. + /// + /// # Examples + /// + /// ``` + /// use std::io::{Error, ErrorKind}; + /// + /// fn print_error(err: Error) { + /// if let Some(inner_err) = err.into_inner() { + /// println!("Inner error: {}", inner_err); + /// } else { + /// println!("No inner error"); + /// } + /// } + /// + /// fn main() { + /// // Will print "No inner error". + /// print_error(Error::last_os_error()); + /// // Will print "Inner error: ...". + /// print_error(Error::new(ErrorKind::Other, "oh no!")); + /// } + /// ``` + #[stable(feature = "io_error_inner", since = "1.3.0")] + pub fn into_inner(self) -> Option> { + match self.repr { + Repr::Os(..) => None, + Repr::Simple(..) => None, + Repr::Custom(c) => Some(c.error) + } + } + + /// Returns the corresponding `ErrorKind` for this error. + /// + /// # Examples + /// + /// ``` + /// use std::io::{Error, ErrorKind}; + /// + /// fn print_error(err: Error) { + /// println!("{:?}", err.kind()); + /// } + /// + /// fn main() { + /// // Will print "No inner error". + /// print_error(Error::last_os_error()); + /// // Will print "Inner error: ...". + /// print_error(Error::new(ErrorKind::AddrInUse, "oh no!")); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn kind(&self) -> ErrorKind { + match self.repr { + Repr::Os(code) => sys::decode_error_kind(code), + Repr::Custom(ref c) => c.kind, + Repr::Simple(kind) => kind, + } + } +} + +impl fmt::Debug for Repr { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match *self { + Repr::Os(ref code) => + 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) => { + let detail = sys::os::error_string(code); + write!(fmt, "{} (os error {})", detail, code) + } + Repr::Custom(ref c) => c.error.fmt(fmt), + Repr::Simple(kind) => write!(fmt, "{}", kind.as_str()), + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl error::Error for Error { + fn description(&self) -> &str { + match self.repr { + Repr::Os(..) | Repr::Simple(..) => self.kind().as_str(), + Repr::Custom(ref c) => c.error.description(), + } + } + + fn cause(&self) -> Option<&error::Error> { + match self.repr { + Repr::Os(..) => None, + Repr::Simple(..) => None, + Repr::Custom(ref c) => c.error.cause(), + } + } +} + +fn _assert_error_is_sync_send() { + fn _is_sync_send() {} + _is_sync_send::(); +} + +#[cfg(test)] +mod test { + use super::{Error, ErrorKind}; + use error; + use fmt; + use sys::os::error_string; + + #[test] + fn test_debug_error() { + let code = 6; + let msg = error_string(code); + let err = Error { repr: super::Repr::Os(code) }; + let expected = format!("Error {{ repr: Os {{ code: {:?}, message: {:?} }} }}", code, msg); + assert_eq!(format!("{:?}", err), expected); + } + + #[test] + fn test_downcasting() { + #[derive(Debug)] + struct TestError; + + impl fmt::Display for TestError { + fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } + } + + impl error::Error for TestError { + fn description(&self) -> &str { + "asdf" + } + } + + // we have to call all of these UFCS style right now since method + // resolution won't implicitly drop the Send+Sync bounds + let mut err = Error::new(ErrorKind::Other, TestError); + assert!(err.get_ref().unwrap().is::()); + assert_eq!("asdf", err.get_ref().unwrap().description()); + assert!(err.get_mut().unwrap().is::()); + let extracted = err.into_inner().unwrap(); + extracted.downcast::().unwrap(); + } +} diff --git a/ctr-std/src/io/impls.rs b/ctr-std/src/io/impls.rs new file mode 100644 index 0000000..6b26c01 --- /dev/null +++ b/ctr-std/src/io/impls.rs @@ -0,0 +1,296 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use cmp; +use io::{self, SeekFrom, Read, Write, Seek, BufRead, Error, ErrorKind}; +use fmt; +use mem; + +// ============================================================================= +// Forwarding implementations + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, R: Read + ?Sized> Read for &'a mut R { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> io::Result { + (**self).read(buf) + } + + #[inline] + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + (**self).read_to_end(buf) + } + + #[inline] + fn read_to_string(&mut self, buf: &mut String) -> io::Result { + (**self).read_to_string(buf) + } + + #[inline] + fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { + (**self).read_exact(buf) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, W: Write + ?Sized> Write for &'a mut W { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { (**self).write(buf) } + + #[inline] + fn flush(&mut self) -> io::Result<()> { (**self).flush() } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + (**self).write_all(buf) + } + + #[inline] + fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> { + (**self).write_fmt(fmt) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, S: Seek + ?Sized> Seek for &'a mut S { + #[inline] + fn seek(&mut self, pos: SeekFrom) -> io::Result { (**self).seek(pos) } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, B: BufRead + ?Sized> BufRead for &'a mut B { + #[inline] + fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() } + + #[inline] + fn consume(&mut self, amt: usize) { (**self).consume(amt) } + + #[inline] + fn read_until(&mut self, byte: u8, buf: &mut Vec) -> io::Result { + (**self).read_until(byte, buf) + } + + #[inline] + fn read_line(&mut self, buf: &mut String) -> io::Result { + (**self).read_line(buf) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Read for Box { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> io::Result { + (**self).read(buf) + } + + #[inline] + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + (**self).read_to_end(buf) + } + + #[inline] + fn read_to_string(&mut self, buf: &mut String) -> io::Result { + (**self).read_to_string(buf) + } + + #[inline] + fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { + (**self).read_exact(buf) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl Write for Box { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { (**self).write(buf) } + + #[inline] + fn flush(&mut self) -> io::Result<()> { (**self).flush() } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + (**self).write_all(buf) + } + + #[inline] + fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> { + (**self).write_fmt(fmt) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl Seek for Box { + #[inline] + fn seek(&mut self, pos: SeekFrom) -> io::Result { (**self).seek(pos) } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl BufRead for Box { + #[inline] + fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() } + + #[inline] + fn consume(&mut self, amt: usize) { (**self).consume(amt) } + + #[inline] + fn read_until(&mut self, byte: u8, buf: &mut Vec) -> io::Result { + (**self).read_until(byte, buf) + } + + #[inline] + fn read_line(&mut self, buf: &mut String) -> io::Result { + (**self).read_line(buf) + } +} + +// ============================================================================= +// In-memory buffer implementations + +/// Read is implemented for `&[u8]` by copying from the slice. +/// +/// Note that reading updates the slice to point to the yet unread part. +/// The slice will be empty when EOF is reached. +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> Read for &'a [u8] { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let amt = cmp::min(buf.len(), self.len()); + let (a, b) = self.split_at(amt); + buf[..amt].copy_from_slice(a); + *self = b; + Ok(amt) + } + + #[inline] + fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { + if buf.len() > self.len() { + return Err(Error::new(ErrorKind::UnexpectedEof, + "failed to fill whole buffer")); + } + let (a, b) = self.split_at(buf.len()); + buf.copy_from_slice(a); + *self = b; + Ok(()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> BufRead for &'a [u8] { + #[inline] + fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(*self) } + + #[inline] + fn consume(&mut self, amt: usize) { *self = &self[amt..]; } +} + +/// Write is implemented for `&mut [u8]` by copying into the slice, overwriting +/// its data. +/// +/// Note that writing updates the slice to point to the yet unwritten part. +/// The slice will be empty when it has been completely overwritten. +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> Write for &'a mut [u8] { + #[inline] + fn write(&mut self, data: &[u8]) -> io::Result { + let amt = cmp::min(data.len(), self.len()); + let (a, b) = mem::replace(self, &mut []).split_at_mut(amt); + a.copy_from_slice(&data[..amt]); + *self = b; + Ok(amt) + } + + #[inline] + fn write_all(&mut self, data: &[u8]) -> io::Result<()> { + if self.write(data)? == data.len() { + Ok(()) + } else { + Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer")) + } + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { Ok(()) } +} + +/// Write is implemented for `Vec` by appending to the vector. +/// The vector will grow as needed. +#[stable(feature = "rust1", since = "1.0.0")] +impl Write for Vec { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + self.extend_from_slice(buf); + Ok(buf.len()) + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + self.extend_from_slice(buf); + Ok(()) + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { Ok(()) } +} + +#[cfg(test)] +mod tests { + use io::prelude::*; + use test; + + #[bench] + fn bench_read_slice(b: &mut test::Bencher) { + let buf = [5; 1024]; + let mut dst = [0; 128]; + + b.iter(|| { + let mut rd = &buf[..]; + for _ in 0..8 { + let _ = rd.read(&mut dst); + test::black_box(&dst); + } + }) + } + + #[bench] + fn bench_write_slice(b: &mut test::Bencher) { + let mut buf = [0; 1024]; + let src = [5; 128]; + + b.iter(|| { + let mut wr = &mut buf[..]; + for _ in 0..8 { + let _ = wr.write_all(&src); + test::black_box(&wr); + } + }) + } + + #[bench] + fn bench_read_vec(b: &mut test::Bencher) { + let buf = vec![5; 1024]; + let mut dst = [0; 128]; + + b.iter(|| { + let mut rd = &buf[..]; + for _ in 0..8 { + let _ = rd.read(&mut dst); + test::black_box(&dst); + } + }) + } + + #[bench] + fn bench_write_vec(b: &mut test::Bencher) { + let mut buf = Vec::with_capacity(1024); + let src = [5; 128]; + + b.iter(|| { + let mut wr = &mut buf[..]; + for _ in 0..8 { + let _ = wr.write_all(&src); + test::black_box(&wr); + } + }) + } +} diff --git a/ctr-std/src/io/mod.rs b/ctr-std/src/io/mod.rs new file mode 100644 index 0000000..1653790 --- /dev/null +++ b/ctr-std/src/io/mod.rs @@ -0,0 +1,1990 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Traits, helpers, and type definitions for core I/O functionality. +//! +//! The `std::io` module contains a number of common things you'll need +//! when doing input and output. The most core part of this module is +//! the [`Read`] and [`Write`] traits, which provide the +//! most general interface for reading and writing input and output. +//! +//! # Read and Write +//! +//! Because they are traits, [`Read`] and [`Write`] are implemented by a number +//! of other types, and you can implement them for your types too. As such, +//! you'll see a few different types of I/O throughout the documentation in +//! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec`]s. For +//! example, `Read` adds a `read()` method, which we can use on `File`s: +//! +//! ``` +//! use std::io; +//! use std::io::prelude::*; +//! use std::fs::File; +//! +//! # fn foo() -> io::Result<()> { +//! let mut f = try!(File::open("foo.txt")); +//! let mut buffer = [0; 10]; +//! +//! // read up to 10 bytes +//! try!(f.read(&mut buffer)); +//! +//! println!("The bytes: {:?}", buffer); +//! # Ok(()) +//! # } +//! ``` +//! +//! [`Read`] and [`Write`] are so important, implementors of the two traits have a +//! nickname: readers and writers. So you'll sometimes see 'a reader' instead +//! of 'a type that implements the [`Read`] trait'. Much easier! +//! +//! ## Seek and BufRead +//! +//! Beyond that, there are two important traits that are provided: [`Seek`] +//! and [`BufRead`]. Both of these build on top of a reader to control +//! how the reading happens. [`Seek`] lets you control where the next byte is +//! coming from: +//! +//! ``` +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::SeekFrom; +//! use std::fs::File; +//! +//! # fn foo() -> io::Result<()> { +//! let mut f = try!(File::open("foo.txt")); +//! let mut buffer = [0; 10]; +//! +//! // skip to the last 10 bytes of the file +//! try!(f.seek(SeekFrom::End(-10))); +//! +//! // read up to 10 bytes +//! try!(f.read(&mut buffer)); +//! +//! println!("The bytes: {:?}", buffer); +//! # Ok(()) +//! # } +//! ``` +//! +//! [`BufRead`] uses an internal buffer to provide a number of other ways to read, but +//! to show it off, we'll need to talk about buffers in general. Keep reading! +//! +//! ## BufReader and BufWriter +//! +//! Byte-based interfaces are unwieldy and can be inefficient, as we'd need to be +//! making near-constant calls to the operating system. To help with this, +//! `std::io` comes with two structs, [`BufReader`] and [`BufWriter`], which wrap +//! readers and writers. The wrapper uses a buffer, reducing the number of +//! calls and providing nicer methods for accessing exactly what you want. +//! +//! For example, [`BufReader`] works with the [`BufRead`] trait to add extra +//! methods to any reader: +//! +//! ``` +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::BufReader; +//! use std::fs::File; +//! +//! # fn foo() -> io::Result<()> { +//! let f = try!(File::open("foo.txt")); +//! let mut reader = BufReader::new(f); +//! let mut buffer = String::new(); +//! +//! // read a line into buffer +//! try!(reader.read_line(&mut buffer)); +//! +//! println!("{}", buffer); +//! # Ok(()) +//! # } +//! ``` +//! +//! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call +//! to [`write()`]: +//! +//! ``` +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::BufWriter; +//! use std::fs::File; +//! +//! # fn foo() -> io::Result<()> { +//! let f = try!(File::create("foo.txt")); +//! { +//! let mut writer = BufWriter::new(f); +//! +//! // write a byte to the buffer +//! try!(writer.write(&[42])); +//! +//! } // the buffer is flushed once writer goes out of scope +//! +//! # Ok(()) +//! # } +//! ``` +//! +//! ## Standard input and output +//! +//! A very common source of input is standard input: +//! +//! ``` +//! use std::io; +//! +//! # fn foo() -> io::Result<()> { +//! let mut input = String::new(); +//! +//! try!(io::stdin().read_line(&mut input)); +//! +//! println!("You typed: {}", input.trim()); +//! # Ok(()) +//! # } +//! ``` +//! +//! And a very common source of output is standard output: +//! +//! ``` +//! use std::io; +//! use std::io::prelude::*; +//! +//! # fn foo() -> io::Result<()> { +//! try!(io::stdout().write(&[42])); +//! # Ok(()) +//! # } +//! ``` +//! +//! Of course, using [`io::stdout()`] directly is less common than something like +//! [`println!`]. +//! +//! ## Iterator types +//! +//! A large number of the structures provided by `std::io` are for various +//! ways of iterating over I/O. For example, [`Lines`] is used to split over +//! lines: +//! +//! ``` +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::BufReader; +//! use std::fs::File; +//! +//! # fn foo() -> io::Result<()> { +//! let f = try!(File::open("foo.txt")); +//! let reader = BufReader::new(f); +//! +//! for line in reader.lines() { +//! println!("{}", try!(line)); +//! } +//! +//! # Ok(()) +//! # } +//! ``` +//! +//! ## Functions +//! +//! There are a number of [functions][functions-list] that offer access to various +//! features. For example, we can use three of these functions to copy everything +//! from standard input to standard output: +//! +//! ``` +//! use std::io; +//! +//! # fn foo() -> io::Result<()> { +//! try!(io::copy(&mut io::stdin(), &mut io::stdout())); +//! # Ok(()) +//! # } +//! ``` +//! +//! [functions-list]: #functions-1 +//! +//! ## io::Result +//! +//! Last, but certainly not least, is [`io::Result`]. This type is used +//! as the return type of many `std::io` functions that can cause an error, and +//! can be returned from your own functions as well. Many of the examples in this +//! module use the [`try!`] macro: +//! +//! ``` +//! use std::io; +//! +//! fn read_input() -> io::Result<()> { +//! let mut input = String::new(); +//! +//! try!(io::stdin().read_line(&mut input)); +//! +//! println!("You typed: {}", input.trim()); +//! +//! Ok(()) +//! } +//! ``` +//! +//! The return type of `read_input()`, [`io::Result<()>`][`io::Result`], is a very +//! common type for functions which don't have a 'real' return value, but do want to +//! return errors if they happen. In this case, the only purpose of this function is +//! to read the line and print it, so we use `()`. +//! +//! ## Platform-specific behavior +//! +//! Many I/O functions throughout the standard library are documented to indicate +//! what various library or syscalls they are delegated to. This is done to help +//! applications both understand what's happening under the hood as well as investigate +//! any possibly unclear semantics. Note, however, that this is informative, not a binding +//! contract. The implementation of many of these functions are subject to change over +//! time and may call fewer or more syscalls/library functions. +//! +//! [`Read`]: trait.Read.html +//! [`Write`]: trait.Write.html +//! [`Seek`]: trait.Seek.html +//! [`BufRead`]: trait.BufRead.html +//! [`File`]: ../fs/struct.File.html +//! [`TcpStream`]: ../net/struct.TcpStream.html +//! [`Vec`]: ../vec/struct.Vec.html +//! [`BufReader`]: struct.BufReader.html +//! [`BufWriter`]: struct.BufWriter.html +//! [`write()`]: 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; +use error as std_error; +use fmt; +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 mod prelude; +mod buffered; +mod cursor; +mod error; +mod impls; +mod util; +mod print; + +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 +// implementation will just call `.as_mut_vec()` and then delegate to a +// byte-oriented reading method, but we must ensure that when returning we never +// leave `buf` in a state such that it contains invalid UTF-8 in its bounds. +// +// To this end, we use an RAII guard (to protect against panics) which updates +// the length of the string when it is dropped. This guard initially truncates +// the string to the prior length and only after we've validated that the +// new contents are valid UTF-8 do we allow it to set a longer length. +// +// The unsafety in this function is twofold: +// +// 1. We're looking at the raw bytes of `buf`, so we take on the burden of UTF-8 +// checks. +// 2. We're passing a raw buffer to the function `f`, and it is expected that +// the function only *appends* bytes to the buffer. We'll get undefined +// behavior if existing bytes are overwritten to have non-UTF-8 data. +fn append_to_string(buf: &mut String, f: F) -> Result + where F: FnOnce(&mut Vec) -> Result +{ + struct Guard<'a> { s: &'a mut Vec, len: usize } + impl<'a> Drop for Guard<'a> { + fn drop(&mut self) { + unsafe { self.s.set_len(self.len); } + } + } + + unsafe { + let mut g = Guard { len: buf.len(), s: buf.as_mut_vec() }; + let ret = f(g.s); + if str::from_utf8(&g.s[g.len..]).is_err() { + ret.and_then(|_| { + Err(Error::new(ErrorKind::InvalidData, + "stream did not contain valid UTF-8")) + }) + } else { + g.len = g.s.len(); + ret + } + } +} + +// This uses an adaptive system to extend the vector when it fills. We want to +// avoid paying to allocate and zero a huge chunk of memory if the reader only +// has 4 bytes while still making large reads if the reader does have a ton +// of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every +// time is 4,500 times (!) slower than this if the reader has a very small +// amount of data to return. +fn read_to_end(r: &mut R, buf: &mut Vec) -> Result { + let start_len = buf.len(); + let mut len = start_len; + let mut new_write_size = 16; + let ret; + loop { + if len == buf.len() { + if new_write_size < DEFAULT_BUF_SIZE { + new_write_size *= 2; + } + buf.resize(len + new_write_size, 0); + } + + match r.read(&mut buf[len..]) { + Ok(0) => { + ret = Ok(len - start_len); + break; + } + Ok(n) => len += n, + Err(ref e) if e.kind() == ErrorKind::Interrupted => {} + Err(e) => { + ret = Err(e); + break; + } + } + } + + buf.truncate(len); + ret +} + +/// The `Read` trait allows for reading bytes from a source. +/// +/// Implementors of the `Read` trait are sometimes called 'readers'. +/// +/// Readers are defined by one required method, `read()`. Each call to `read` +/// will attempt to pull bytes from this source into a provided buffer. A +/// number of other methods are implemented in terms of `read()`, giving +/// implementors a number of ways to read bytes while only needing to implement +/// a single method. +/// +/// Readers are intended to be composable with one another. Many implementors +/// throughout `std::io` take and provide types which implement the `Read` +/// trait. +/// +/// Please note that each call to `read` may involve a system call, and +/// therefore, using something that implements [`BufRead`][bufread], such as +/// [`BufReader`][bufreader], will be more efficient. +/// +/// [bufread]: trait.BufRead.html +/// [bufreader]: struct.BufReader.html +/// +/// # Examples +/// +/// [`File`][file]s implement `Read`: +/// +/// [file]: ../fs/struct.File.html +/// +/// ``` +/// use std::io; +/// use std::io::prelude::*; +/// use std::fs::File; +/// +/// # fn foo() -> io::Result<()> { +/// let mut f = try!(File::open("foo.txt")); +/// let mut buffer = [0; 10]; +/// +/// // read up to 10 bytes +/// try!(f.read(&mut buffer)); +/// +/// let mut buffer = vec![0; 10]; +/// // read the whole file +/// try!(f.read_to_end(&mut buffer)); +/// +/// // read into a String, so that you don't need to do the conversion. +/// let mut buffer = String::new(); +/// try!(f.read_to_string(&mut buffer)); +/// +/// // and more! See the other methods for more details. +/// # 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. + /// + /// This function does not provide any guarantees about whether it blocks + /// waiting for data, but if an object needs to block for a read but cannot + /// it will typically signal this via an `Err` return value. + /// + /// If the return value of this method is `Ok(n)`, then it must be + /// guaranteed that `0 <= n <= buf.len()`. A nonzero `n` value indicates + /// that the buffer `buf` has been filled in with `n` bytes of data from this + /// source. If `n` is `0`, then it can indicate one of two scenarios: + /// + /// 1. This reader has reached its "end of file" and will likely no longer + /// be able to produce bytes. Note that this does not mean that the + /// reader will *always* no longer be able to produce bytes. + /// 2. The buffer specified was 0 bytes in length. + /// + /// No guarantees are provided about the contents of `buf` when this + /// function is called, implementations cannot rely on any property of the + /// contents of `buf` being true. It is recommended that implementations + /// only write data to `buf` instead of reading its contents. + /// + /// # Errors + /// + /// If this function encounters any form of I/O or other error, an error + /// variant will be returned. If an error is returned then it must be + /// guaranteed that no bytes were read. + /// + /// # Examples + /// + /// [`File`][file]s implement `Read`: + /// + /// [file]: ../fs/struct.File.html + /// + /// ``` + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut f = try!(File::open("foo.txt")); + /// let mut buffer = [0; 10]; + /// + /// // read 10 bytes + /// try!(f.read(&mut buffer[..])); + /// # 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`. + /// + /// All bytes read from this source will be appended to the specified buffer + /// `buf`. This function will continuously call `read` to append more data to + /// `buf` until `read` returns either `Ok(0)` or an error of + /// non-`ErrorKind::Interrupted` kind. + /// + /// If successful, this function will return the total number of bytes read. + /// + /// # Errors + /// + /// If this function encounters an error of the kind + /// `ErrorKind::Interrupted` then the error is ignored and the operation + /// will continue. + /// + /// If any other read error is encountered then this function immediately + /// returns. Any bytes which have already been read will be appended to + /// `buf`. + /// + /// # Examples + /// + /// [`File`][file]s implement `Read`: + /// + /// [file]: ../fs/struct.File.html + /// + /// ``` + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut f = try!(File::open("foo.txt")); + /// let mut buffer = Vec::new(); + /// + /// // read the whole file + /// try!(f.read_to_end(&mut buffer)); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn read_to_end(&mut self, buf: &mut Vec) -> Result { + read_to_end(self, buf) + } + + /// Read all bytes until EOF in this source, placing them into `buf`. + /// + /// If successful, this function returns the number of bytes which were read + /// and appended to `buf`. + /// + /// # Errors + /// + /// If the data in this stream is *not* valid UTF-8 then an error is + /// returned and `buf` is unchanged. + /// + /// See [`read_to_end()`][readtoend] for other error semantics. + /// + /// [readtoend]: #method.read_to_end + /// + /// # Examples + /// + /// [`File`][file]s implement `Read`: + /// + /// [file]: ../fs/struct.File.html + /// + /// ``` + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut f = try!(File::open("foo.txt")); + /// let mut buffer = String::new(); + /// + /// try!(f.read_to_string(&mut buffer)); + /// # 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` + // method to fill it up. An arbitrary implementation could overwrite the + // entire contents of the vector, not just append to it (which is what + // we are expecting). + // + // To prevent extraneously checking the UTF-8-ness of the entire buffer + // we pass it to our hardcoded `read_to_end` implementation which we + // know is guaranteed to only read data into the end of the buffer. + append_to_string(buf, |b| read_to_end(self, b)) + } + + /// Read the exact number of bytes required to fill `buf`. + /// + /// This function reads as many bytes as necessary to completely fill the + /// specified buffer `buf`. + /// + /// No guarantees are provided about the contents of `buf` when this + /// function is called, implementations cannot rely on any property of the + /// contents of `buf` being true. It is recommended that implementations + /// only write data to `buf` instead of reading its contents. + /// + /// # Errors + /// + /// If this function encounters an error of the kind + /// `ErrorKind::Interrupted` then the error is ignored and the operation + /// will continue. + /// + /// If this function encounters an "end of file" before completely filling + /// the buffer, it returns an error of the kind `ErrorKind::UnexpectedEof`. + /// The contents of `buf` are unspecified in this case. + /// + /// If any other read error is encountered then this function immediately + /// returns. The contents of `buf` are unspecified in this case. + /// + /// If this function returns an error, it is unspecified how many bytes it + /// has read, but it will never read more than would be necessary to + /// completely fill the buffer. + /// + /// # Examples + /// + /// [`File`][file]s implement `Read`: + /// + /// [file]: ../fs/struct.File.html + /// + /// ``` + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut f = try!(File::open("foo.txt")); + /// let mut buffer = [0; 10]; + /// + /// // read exactly 10 bytes + /// try!(f.read_exact(&mut buffer)); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "read_exact", since = "1.6.0")] + fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<()> { + while !buf.is_empty() { + match self.read(buf) { + Ok(0) => break, + Ok(n) => { let tmp = buf; buf = &mut tmp[n..]; } + Err(ref e) if e.kind() == ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + if !buf.is_empty() { + Err(Error::new(ErrorKind::UnexpectedEof, + "failed to fill whole buffer")) + } else { + Ok(()) + } + } + + /// Creates a "by reference" adaptor for this instance of `Read`. + /// + /// The returned adaptor also implements `Read` and will simply borrow this + /// current reader. + /// + /// # Examples + /// + /// [`File`][file]s implement `Read`: + /// + /// [file]: ../fs/struct.File.html + /// + /// ``` + /// use std::io; + /// use std::io::Read; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut f = try!(File::open("foo.txt")); + /// let mut buffer = Vec::new(); + /// let mut other_buffer = Vec::new(); + /// + /// { + /// let reference = f.by_ref(); + /// + /// // read at most 5 bytes + /// try!(reference.take(5).read_to_end(&mut buffer)); + /// + /// } // drop our &mut reference so we can use f again + /// + /// // original file still usable, read the rest + /// try!(f.read_to_end(&mut other_buffer)); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn by_ref(&mut self) -> &mut Self where Self: Sized { self } + + /// Transforms this `Read` instance to an `Iterator` over its bytes. + /// + /// The returned type implements `Iterator` where the `Item` is `Result`. The yielded item is `Ok` if a byte was successfully read and + /// `Err` otherwise for I/O errors. EOF is mapped to returning `None` from + /// this iterator. + /// + /// # Examples + /// + /// [`File`][file]s implement `Read`: + /// + /// [file]: ../fs/struct.File.html + /// + /// ``` + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut f = try!(File::open("foo.txt")); + /// + /// for byte in f.bytes() { + /// println!("{}", byte.unwrap()); + /// } + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn bytes(self) -> Bytes where Self: Sized { + Bytes { inner: self } + } + + /// Transforms this `Read` instance to an `Iterator` over `char`s. + /// + /// This adaptor will attempt to interpret this reader as a UTF-8 encoded + /// sequence of characters. The returned iterator will return `None` once + /// EOF is reached for this reader. Otherwise each element yielded will be a + /// `Result` where `E` may contain information about what I/O error + /// occurred or where decoding failed. + /// + /// Currently this adaptor will discard intermediate data read, and should + /// be avoided if this is not desired. + /// + /// # Examples + /// + /// [`File`][file]s implement `Read`: + /// + /// [file]: ../fs/struct.File.html + /// + /// ``` + /// #![feature(io)] + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut f = try!(File::open("foo.txt")); + /// + /// for c in f.chars() { + /// println!("{}", c.unwrap()); + /// } + /// # 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 } + } + + /// Creates an adaptor which will chain this stream with another. + /// + /// The returned `Read` instance will first read all bytes from this object + /// until EOF is encountered. Afterwards the output is equivalent to the + /// output of `next`. + /// + /// # Examples + /// + /// [`File`][file]s implement `Read`: + /// + /// [file]: ../fs/struct.File.html + /// + /// ``` + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut f1 = try!(File::open("foo.txt")); + /// let mut f2 = try!(File::open("bar.txt")); + /// + /// let mut handle = f1.chain(f2); + /// let mut buffer = String::new(); + /// + /// // read the value into a String. We could use any Read method here, + /// // this is just one example. + /// try!(handle.read_to_string(&mut buffer)); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn chain(self, next: R) -> Chain where Self: Sized { + Chain { first: self, second: next, done_first: false } + } + + /// Creates an adaptor which will read at most `limit` bytes from it. + /// + /// This function returns a new instance of `Read` which will read at most + /// `limit` bytes, after which it will always return EOF (`Ok(0)`). Any + /// read errors will not count towards the number of bytes read and future + /// calls to `read` may succeed. + /// + /// # Examples + /// + /// [`File`][file]s implement `Read`: + /// + /// [file]: ../fs/struct.File.html + /// + /// ``` + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut f = try!(File::open("foo.txt")); + /// let mut buffer = [0; 5]; + /// + /// // read at most five bytes + /// let mut handle = f.take(5); + /// + /// try!(handle.read(&mut buffer)); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn take(self, limit: u64) -> Take where Self: Sized { + Take { inner: self, limit: limit } + } +} + +/// A trait for objects which are byte-oriented sinks. +/// +/// Implementors of the `Write` trait are sometimes called 'writers'. +/// +/// Writers are defined by two required methods, `write()` and `flush()`: +/// +/// * The `write()` method will attempt to write some data into the object, +/// returning how many bytes were successfully written. +/// +/// * The `flush()` method is useful for adaptors and explicit buffers +/// themselves for ensuring that all buffered data has been pushed out to the +/// 'true sink'. +/// +/// Writers are intended to be composable with one another. Many implementors +/// throughout `std::io` take and provide types which implement the `Write` +/// trait. +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::fs::File; +/// +/// # fn foo() -> std::io::Result<()> { +/// let mut buffer = try!(File::create("foo.txt")); +/// +/// try!(buffer.write(b"some bytes")); +/// # Ok(()) +/// # } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub trait Write { + /// Write a buffer into this object, returning how many bytes were written. + /// + /// This function will attempt to write the entire contents of `buf`, but + /// the entire write may not succeed, or the write may also generate an + /// error. A call to `write` represents *at most one* attempt to write to + /// any wrapped object. + /// + /// Calls to `write` are not guaranteed to block waiting for data to be + /// written, and a write which would otherwise block can be indicated through + /// an `Err` variant. + /// + /// If the return value is `Ok(n)` then it must be guaranteed that + /// `0 <= n <= buf.len()`. A return value of `0` typically means that the + /// underlying object is no longer able to accept bytes and will likely not + /// be able to in the future as well, or that the buffer provided is empty. + /// + /// # Errors + /// + /// Each call to `write` may generate an I/O error indicating that the + /// operation could not be completed. If an error is returned then no bytes + /// in the buffer were written to this writer. + /// + /// It is **not** considered an error if the entire buffer could not be + /// written to this writer. + /// + /// # Examples + /// + /// ``` + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut buffer = try!(File::create("foo.txt")); + /// + /// try!(buffer.write(b"some bytes")); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn write(&mut self, buf: &[u8]) -> Result; + + /// Flush this output stream, ensuring that all intermediately buffered + /// contents reach their destination. + /// + /// # Errors + /// + /// It is considered an error if not all bytes could be written due to + /// I/O errors or EOF being reached. + /// + /// # Examples + /// + /// ``` + /// use std::io::prelude::*; + /// use std::io::BufWriter; + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut buffer = BufWriter::new(try!(File::create("foo.txt"))); + /// + /// try!(buffer.write(b"some bytes")); + /// try!(buffer.flush()); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn flush(&mut self) -> Result<()>; + + /// Attempts to write an entire buffer into this write. + /// + /// This method will continuously call `write` while there is more data to + /// write. This method will not return until the entire buffer has been + /// successfully written or an error occurs. The first error generated from + /// this method will be returned. + /// + /// # Errors + /// + /// This function will return the first error that `write` returns. + /// + /// # Examples + /// + /// ``` + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut buffer = try!(File::create("foo.txt")); + /// + /// try!(buffer.write_all(b"some bytes")); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn write_all(&mut self, mut buf: &[u8]) -> Result<()> { + while !buf.is_empty() { + match self.write(buf) { + Ok(0) => return Err(Error::new(ErrorKind::WriteZero, + "failed to write whole buffer")), + Ok(n) => buf = &buf[n..], + Err(ref e) if e.kind() == ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + Ok(()) + } + + /// Writes a formatted string into this writer, returning any error + /// encountered. + /// + /// This method is primarily used to interface with the + /// [`format_args!`][formatargs] macro, but it is rare that this should + /// explicitly be called. The [`write!`][write] macro should be favored to + /// invoke this method instead. + /// + /// [formatargs]: ../macro.format_args.html + /// [write]: ../macro.write.html + /// + /// This function internally uses the [`write_all`][writeall] method on + /// this trait and hence will continuously write data so long as no errors + /// are received. This also means that partial writes are not indicated in + /// this signature. + /// + /// [writeall]: #method.write_all + /// + /// # Errors + /// + /// This function will return any I/O error reported while formatting. + /// + /// # Examples + /// + /// ``` + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut buffer = try!(File::create("foo.txt")); + /// + /// // this call + /// try!(write!(buffer, "{:.*}", 2, 1.234567)); + /// // turns into this: + /// try!(buffer.write_fmt(format_args!("{:.*}", 2, 1.234567))); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<()> { + // Create a shim which translates a Write to a fmt::Write and saves + // off I/O errors. instead of discarding them + struct Adaptor<'a, T: ?Sized + 'a> { + inner: &'a mut T, + error: Result<()>, + } + + impl<'a, T: Write + ?Sized> fmt::Write for Adaptor<'a, T> { + fn write_str(&mut self, s: &str) -> fmt::Result { + match self.inner.write_all(s.as_bytes()) { + Ok(()) => Ok(()), + Err(e) => { + self.error = Err(e); + Err(fmt::Error) + } + } + } + } + + let mut output = Adaptor { inner: self, error: Ok(()) }; + match fmt::write(&mut output, fmt) { + Ok(()) => Ok(()), + Err(..) => { + // check if the error came from the underlying `Write` or not + if output.error.is_err() { + output.error + } else { + Err(Error::new(ErrorKind::Other, "formatter error")) + } + } + } + } + + /// Creates a "by reference" adaptor for this instance of `Write`. + /// + /// The returned adaptor also implements `Write` and will simply borrow this + /// current writer. + /// + /// # Examples + /// + /// ``` + /// use std::io::Write; + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut buffer = try!(File::create("foo.txt")); + /// + /// let reference = buffer.by_ref(); + /// + /// // we can use reference just like our original buffer + /// try!(reference.write_all(b"some bytes")); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn by_ref(&mut self) -> &mut Self where Self: Sized { self } +} + +/// The `Seek` trait provides a cursor which can be moved within a stream of +/// bytes. +/// +/// The stream typically has a fixed size, allowing seeking relative to either +/// end or the current offset. +/// +/// # Examples +/// +/// [`File`][file]s implement `Seek`: +/// +/// [file]: ../fs/struct.File.html +/// +/// ``` +/// use std::io; +/// use std::io::prelude::*; +/// use std::fs::File; +/// use std::io::SeekFrom; +/// +/// # fn foo() -> io::Result<()> { +/// let mut f = try!(File::open("foo.txt")); +/// +/// // move the cursor 42 bytes from the start of the file +/// try!(f.seek(SeekFrom::Start(42))); +/// # Ok(()) +/// # } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub trait Seek { + /// Seek to an offset, in bytes, in a stream. + /// + /// A seek beyond the end of a stream is allowed, but implementation + /// defined. + /// + /// If the seek operation completed successfully, + /// this method returns the new position from the start of the stream. + /// That position can be used later with [`SeekFrom::Start`]. + /// + /// # Errors + /// + /// Seeking to a negative offset is considered an error. + /// + /// [`SeekFrom::Start`]: enum.SeekFrom.html#variant.Start + #[stable(feature = "rust1", since = "1.0.0")] + fn seek(&mut self, pos: SeekFrom) -> Result; +} + +/// Enumeration of possible methods to seek within an I/O object. +/// +/// It is used by the [`Seek`] trait. +/// +/// [`Seek`]: trait.Seek.html +#[derive(Copy, PartialEq, Eq, Clone, Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub enum SeekFrom { + /// Set the offset to the provided number of bytes. + #[stable(feature = "rust1", since = "1.0.0")] + Start(#[stable(feature = "rust1", since = "1.0.0")] u64), + + /// Set the offset to the size of this object plus the specified number of + /// bytes. + /// + /// It is possible to seek beyond the end of an object, but it's an error to + /// seek before byte 0. + #[stable(feature = "rust1", since = "1.0.0")] + End(#[stable(feature = "rust1", since = "1.0.0")] i64), + + /// Set the offset to the current position plus the specified number of + /// bytes. + /// + /// It is possible to seek beyond the end of an object, but it's an error to + /// seek before byte 0. + #[stable(feature = "rust1", since = "1.0.0")] + Current(#[stable(feature = "rust1", since = "1.0.0")] i64), +} + +fn read_until(r: &mut R, delim: u8, buf: &mut Vec) + -> Result { + let mut read = 0; + loop { + let (done, used) = { + let available = match r.fill_buf() { + Ok(n) => n, + Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, + Err(e) => return Err(e) + }; + match memchr::memchr(delim, available) { + Some(i) => { + buf.extend_from_slice(&available[..i + 1]); + (true, i + 1) + } + None => { + buf.extend_from_slice(available); + (false, available.len()) + } + } + }; + r.consume(used); + read += used; + if done || used == 0 { + return Ok(read); + } + } +} + +/// A `BufRead` is a type of `Read`er which has an internal buffer, allowing it +/// to perform extra ways of reading. +/// +/// For example, reading line-by-line is inefficient without using a buffer, so +/// if you want to read by line, you'll need `BufRead`, which includes a +/// [`read_line()`] method as well as a [`lines()`] iterator. +/// +/// # Examples +/// +/// A locked standard input implements `BufRead`: +/// +/// ``` +/// use std::io; +/// use std::io::prelude::*; +/// +/// let stdin = io::stdin(); +/// for line in stdin.lock().lines() { +/// println!("{}", line.unwrap()); +/// } +/// ``` +/// +/// If you have something that implements [`Read`], you can use the [`BufReader` +/// type][`BufReader`] to turn it into a `BufRead`. +/// +/// For example, [`File`] implements [`Read`], but not `BufRead`. +/// [`BufReader`] to the rescue! +/// +/// [`BufReader`]: struct.BufReader.html +/// [`File`]: ../fs/struct.File.html +/// [`read_line()`]: #method.read_line +/// [`lines()`]: #method.lines +/// [`Read`]: trait.Read.html +/// +/// ``` +/// use std::io::{self, BufReader}; +/// use std::io::prelude::*; +/// use std::fs::File; +/// +/// # fn foo() -> io::Result<()> { +/// let f = try!(File::open("foo.txt")); +/// let f = BufReader::new(f); +/// +/// for line in f.lines() { +/// println!("{}", line.unwrap()); +/// } +/// +/// # Ok(()) +/// # } +/// ``` +/// +#[stable(feature = "rust1", since = "1.0.0")] +pub trait BufRead: Read { + /// Fills the internal buffer of this object, returning the buffer contents. + /// + /// This function is a lower-level call. It needs to be paired with the + /// [`consume()`] method to function properly. When calling this + /// method, none of the contents will be "read" in the sense that later + /// calling `read` may return the same contents. As such, [`consume()`] must + /// be called with the number of bytes that are consumed from this buffer to + /// ensure that the bytes are never returned twice. + /// + /// [`consume()`]: #tymethod.consume + /// + /// An empty buffer returned indicates that the stream has reached EOF. + /// + /// # Errors + /// + /// This function will return an I/O error if the underlying reader was + /// read, but returned an error. + /// + /// # Examples + /// + /// A locked standard input implements `BufRead`: + /// + /// ``` + /// use std::io; + /// use std::io::prelude::*; + /// + /// let stdin = io::stdin(); + /// let mut stdin = stdin.lock(); + /// + /// // we can't have two `&mut` references to `stdin`, so use a block + /// // to end the borrow early. + /// let length = { + /// let buffer = stdin.fill_buf().unwrap(); + /// + /// // work with buffer + /// println!("{:?}", buffer); + /// + /// buffer.len() + /// }; + /// + /// // ensure the bytes we worked with aren't returned again later + /// stdin.consume(length); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn fill_buf(&mut self) -> Result<&[u8]>; + + /// Tells this buffer that `amt` bytes have been consumed from the buffer, + /// so they should no longer be returned in calls to `read`. + /// + /// This function is a lower-level call. It needs to be paired with the + /// [`fill_buf()`] method to function properly. This function does + /// not perform any I/O, it simply informs this object that some amount of + /// its buffer, returned from [`fill_buf()`], has been consumed and should + /// no longer be returned. As such, this function may do odd things if + /// [`fill_buf()`] isn't called before calling it. + /// + /// The `amt` must be `<=` the number of bytes in the buffer returned by + /// [`fill_buf()`]. + /// + /// # Examples + /// + /// Since `consume()` is meant to be used with [`fill_buf()`], + /// that method's example includes an example of `consume()`. + /// + /// [`fill_buf()`]: #tymethod.fill_buf + #[stable(feature = "rust1", since = "1.0.0")] + fn consume(&mut self, amt: usize); + + /// Read all bytes into `buf` until the delimiter `byte` or EOF is reached. + /// + /// This function will read bytes from the underlying stream until the + /// delimiter or EOF is found. Once found, all bytes up to, and including, + /// the delimiter (if found) will be appended to `buf`. + /// + /// If successful, this function will return the total number of bytes read. + /// + /// # Errors + /// + /// This function will ignore all instances of [`ErrorKind::Interrupted`] and + /// will otherwise return any errors returned by [`fill_buf()`]. + /// + /// If an I/O error is encountered then all bytes read so far will be + /// present in `buf` and its length will have been adjusted appropriately. + /// + /// # Examples + /// + /// 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::*; + /// + /// fn foo() -> io::Result<()> { + /// let stdin = io::stdin(); + /// let mut stdin = stdin.lock(); + /// let mut buffer = Vec::new(); + /// + /// try!(stdin.read_until(b'a', &mut buffer)); + /// + /// println!("{:?}", buffer); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn read_until(&mut self, byte: u8, buf: &mut Vec) -> Result { + read_until(self, byte, buf) + } + + /// Read all bytes until a newline (the 0xA byte) is reached, and append + /// them to the provided buffer. + /// + /// This function will read bytes from the underlying stream until the + /// newline delimiter (the 0xA byte) or EOF is found. Once found, all bytes + /// up to, and including, the delimiter (if found) will be appended to + /// `buf`. + /// + /// If successful, this function will return the total number of bytes read. + /// + /// # 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. + /// + /// # 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()`] method would be easier, of + /// course. + /// + /// [`lines()`]: #method.lines + /// [`read_until()`]: #method.read_until + /// + /// ``` + /// use std::io; + /// use std::io::prelude::*; + /// + /// let stdin = io::stdin(); + /// let mut stdin = stdin.lock(); + /// let mut buffer = String::new(); + /// + /// while stdin.read_line(&mut buffer).unwrap() > 0 { + /// // work with buffer + /// println!("{:?}", buffer); + /// + /// 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 + // the comments in `read_to_end`. + append_to_string(buf, |b| read_until(self, b'\n', b)) + } + + /// Returns an iterator over the contents of this reader split on the byte + /// `byte`. + /// + /// The iterator returned from this function will return instances of + /// [`io::Result`]`<`[`Vec`]`>`. Each vector returned will *not* have + /// the delimiter byte at the end. + /// + /// This function will yield errors whenever [`read_until()`] would have + /// also yielded an error. + /// + /// # 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::*; + /// + /// let stdin = io::stdin(); + /// + /// for content in stdin.lock().split(b',') { + /// println!("{:?}", content.unwrap()); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn split(self, byte: u8) -> Split where Self: Sized { + Split { buf: self, delim: byte } + } + + /// Returns an iterator over the lines of this reader. + /// + /// The iterator returned from this function will yield instances of + /// [`io::Result`]`<`[`String`]`>`. Each string returned will *not* have a newline + /// byte (the 0xA byte) or CRLF (0xD, 0xA bytes) at the end. + /// + /// [`io::Result`]: type.Result.html + /// [`String`]: ../string/struct.String.html + /// + /// # Examples + /// + /// A locked standard input implements `BufRead`: + /// + /// ``` + /// use std::io; + /// use std::io::prelude::*; + /// + /// let stdin = io::stdin(); + /// + /// for line in stdin.lock().lines() { + /// println!("{}", line.unwrap()); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn lines(self) -> Lines where Self: Sized { + Lines { buf: self } + } +} + +/// Adaptor to chain together two readers. +/// +/// This struct is generally created by calling [`chain()`] on a reader. +/// Please see the documentation of [`chain()`] for more details. +/// +/// [`chain()`]: trait.Read.html#method.chain +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Chain { + first: T, + second: U, + done_first: bool, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Read for Chain { + fn read(&mut self, buf: &mut [u8]) -> Result { + if !self.done_first { + match self.first.read(buf)? { + 0 if buf.len() != 0 => { self.done_first = true; } + n => return Ok(n), + } + } + self.second.read(buf) + } +} + +#[stable(feature = "chain_bufread", since = "1.9.0")] +impl BufRead for Chain { + fn fill_buf(&mut self) -> Result<&[u8]> { + if !self.done_first { + match self.first.fill_buf()? { + buf if buf.len() == 0 => { self.done_first = true; } + buf => return Ok(buf), + } + } + self.second.fill_buf() + } + + fn consume(&mut self, amt: usize) { + if !self.done_first { + self.first.consume(amt) + } else { + self.second.consume(amt) + } + } +} + +/// Reader adaptor which limits the bytes read from an underlying reader. +/// +/// This struct is generally created by calling [`take()`][take] on a reader. +/// Please see the documentation of `take()` for more details. +/// +/// [take]: trait.Read.html#method.take +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Take { + inner: T, + limit: u64, +} + +impl Take { + /// Returns the number of bytes that can be read before this instance will + /// return EOF. + /// + /// # Note + /// + /// This instance may reach EOF after reading fewer bytes than indicated by + /// this method if the underlying `Read` instance reaches EOF. + /// + /// # Examples + /// + /// ``` + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let f = try!(File::open("foo.txt")); + /// + /// // read at most five bytes + /// let handle = f.take(5); + /// + /// println!("limit: {}", handle.limit()); + /// # Ok(()) + /// # } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn limit(&self) -> u64 { self.limit } + + /// 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 + if self.limit == 0 { + return Ok(0); + } + + let max = cmp::min(buf.len() as u64, self.limit) as usize; + let n = self.inner.read(&mut buf[..max])?; + self.limit -= n as u64; + Ok(n) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl BufRead for Take { + fn fill_buf(&mut self) -> Result<&[u8]> { + // Don't call into inner reader at all at EOF because it may still block + if self.limit == 0 { + return Ok(&[]); + } + + let buf = self.inner.fill_buf()?; + let cap = cmp::min(buf.len() as u64, self.limit) as usize; + Ok(&buf[..cap]) + } + + fn consume(&mut self, amt: usize) { + // Don't let callers reset the limit by passing an overlarge value + let amt = cmp::min(amt as u64, self.limit) as usize; + self.limit -= amt as u64; + self.inner.consume(amt); + } +} + +fn read_one_byte(reader: &mut Read) -> Option> { + let mut buf = [0]; + loop { + return match reader.read(&mut buf) { + Ok(0) => None, + Ok(..) => Some(Ok(buf[0])), + Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, + Err(e) => Some(Err(e)), + }; + } +} + +/// An iterator over `u8` values of a reader. +/// +/// This struct is generally created by calling [`bytes()`] on a reader. +/// Please see the documentation of [`bytes()`] for more details. +/// +/// [`bytes()`]: trait.Read.html#method.bytes +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Bytes { + inner: R, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Bytes { + type Item = Result; + + fn next(&mut self) -> Option> { + read_one_byte(&mut self.inner) + } +} + +/// An iterator over the `char`s of a reader. +/// +/// This struct is generally created by calling [`chars()`][chars] on a reader. +/// 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, +} + +/// 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. + NotUtf8, + + /// Variant representing that an I/O error occurred. + Other(Error), +} + +#[unstable(feature = "io", reason = "awaiting stability of Read::chars", + issue = "27802")] +impl Iterator for Chars { + type Item = result::Result; + + fn next(&mut self) -> Option> { + let first_byte = match read_one_byte(&mut self.inner) { + None => return None, + Some(Ok(b)) => b, + Some(Err(e)) => return Some(Err(CharsError::Other(e))), + }; + let width = core_str::utf8_char_width(first_byte); + if width == 1 { return Some(Ok(first_byte as char)) } + if width == 0 { return Some(Err(CharsError::NotUtf8)) } + let mut buf = [first_byte, 0, 0, 0]; + { + let mut start = 1; + while start < width { + match self.inner.read(&mut buf[start..width]) { + Ok(0) => return Some(Err(CharsError::NotUtf8)), + Ok(n) => start += n, + Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, + Err(e) => return Some(Err(CharsError::Other(e))), + } + } + } + Some(match str::from_utf8(&buf[..width]).ok() { + Some(s) => Ok(s.chars().next().unwrap()), + None => Err(CharsError::NotUtf8), + }) + } +} + +#[unstable(feature = "io", reason = "awaiting stability of Read::chars", + issue = "27802")] +impl std_error::Error for CharsError { + fn description(&self) -> &str { + match *self { + CharsError::NotUtf8 => "invalid utf8 encoding", + CharsError::Other(ref e) => std_error::Error::description(e), + } + } + fn cause(&self) -> Option<&std_error::Error> { + match *self { + CharsError::NotUtf8 => None, + CharsError::Other(ref e) => e.cause(), + } + } +} + +#[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 { + CharsError::NotUtf8 => { + "byte stream did not contain valid utf8".fmt(f) + } + CharsError::Other(ref e) => e.fmt(f), + } + } +} + +/// An iterator over the contents of an instance of `BufRead` split on a +/// particular byte. +/// +/// This struct is generally created by calling [`split()`][split] on a +/// `BufRead`. Please see the documentation of `split()` for more details. +/// +/// [split]: trait.BufRead.html#method.split +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Split { + buf: B, + delim: u8, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Split { + type Item = Result>; + + fn next(&mut self) -> Option>> { + let mut buf = Vec::new(); + match self.buf.read_until(self.delim, &mut buf) { + Ok(0) => None, + Ok(_n) => { + if buf[buf.len() - 1] == self.delim { + buf.pop(); + } + Some(Ok(buf)) + } + Err(e) => Some(Err(e)) + } + } +} + +/// An iterator over the lines of an instance of `BufRead`. +/// +/// This struct is generally created by calling [`lines()`][lines] on a +/// `BufRead`. Please see the documentation of `lines()` for more details. +/// +/// [lines]: trait.BufRead.html#method.lines +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Lines { + buf: B, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Lines { + type Item = Result; + + fn next(&mut self) -> Option> { + let mut buf = String::new(); + match self.buf.read_line(&mut buf) { + Ok(0) => None, + Ok(_n) => { + if buf.ends_with("\n") { + buf.pop(); + if buf.ends_with("\r") { + buf.pop(); + } + } + Some(Ok(buf)) + } + Err(e) => Some(Err(e)) + } + } +} + +#[cfg(test)] +mod tests { + use io::prelude::*; + use io; + use super::Cursor; + use test; + use super::repeat; + + #[test] + #[cfg_attr(target_os = "emscripten", ignore)] + fn read_until() { + let mut buf = Cursor::new(&b"12"[..]); + let mut v = Vec::new(); + assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 2); + assert_eq!(v, b"12"); + + let mut buf = Cursor::new(&b"1233"[..]); + let mut v = Vec::new(); + assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 3); + assert_eq!(v, b"123"); + v.truncate(0); + assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 1); + assert_eq!(v, b"3"); + v.truncate(0); + assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 0); + assert_eq!(v, []); + } + + #[test] + fn split() { + let buf = Cursor::new(&b"12"[..]); + let mut s = buf.split(b'3'); + assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']); + assert!(s.next().is_none()); + + let buf = Cursor::new(&b"1233"[..]); + let mut s = buf.split(b'3'); + assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']); + assert_eq!(s.next().unwrap().unwrap(), vec![]); + assert!(s.next().is_none()); + } + + #[test] + fn read_line() { + let mut buf = Cursor::new(&b"12"[..]); + let mut v = String::new(); + assert_eq!(buf.read_line(&mut v).unwrap(), 2); + assert_eq!(v, "12"); + + let mut buf = Cursor::new(&b"12\n\n"[..]); + let mut v = String::new(); + assert_eq!(buf.read_line(&mut v).unwrap(), 3); + assert_eq!(v, "12\n"); + v.truncate(0); + assert_eq!(buf.read_line(&mut v).unwrap(), 1); + assert_eq!(v, "\n"); + v.truncate(0); + assert_eq!(buf.read_line(&mut v).unwrap(), 0); + assert_eq!(v, ""); + } + + #[test] + fn lines() { + let buf = Cursor::new(&b"12\r"[..]); + let mut s = buf.lines(); + assert_eq!(s.next().unwrap().unwrap(), "12\r".to_string()); + assert!(s.next().is_none()); + + let buf = Cursor::new(&b"12\r\n\n"[..]); + let mut s = buf.lines(); + assert_eq!(s.next().unwrap().unwrap(), "12".to_string()); + assert_eq!(s.next().unwrap().unwrap(), "".to_string()); + assert!(s.next().is_none()); + } + + #[test] + fn read_to_end() { + let mut c = Cursor::new(&b""[..]); + let mut v = Vec::new(); + assert_eq!(c.read_to_end(&mut v).unwrap(), 0); + assert_eq!(v, []); + + let mut c = Cursor::new(&b"1"[..]); + let mut v = Vec::new(); + assert_eq!(c.read_to_end(&mut v).unwrap(), 1); + assert_eq!(v, b"1"); + + let cap = 1024 * 1024; + let data = (0..cap).map(|i| (i / 3) as u8).collect::>(); + let mut v = Vec::new(); + let (a, b) = data.split_at(data.len() / 2); + assert_eq!(Cursor::new(a).read_to_end(&mut v).unwrap(), a.len()); + assert_eq!(Cursor::new(b).read_to_end(&mut v).unwrap(), b.len()); + assert_eq!(v, data); + } + + #[test] + fn read_to_string() { + let mut c = Cursor::new(&b""[..]); + let mut v = String::new(); + assert_eq!(c.read_to_string(&mut v).unwrap(), 0); + assert_eq!(v, ""); + + let mut c = Cursor::new(&b"1"[..]); + let mut v = String::new(); + assert_eq!(c.read_to_string(&mut v).unwrap(), 1); + assert_eq!(v, "1"); + + let mut c = Cursor::new(&b"\xff"[..]); + let mut v = String::new(); + assert!(c.read_to_string(&mut v).is_err()); + } + + #[test] + fn read_exact() { + let mut buf = [0; 4]; + + let mut c = Cursor::new(&b""[..]); + assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), + io::ErrorKind::UnexpectedEof); + + let mut c = Cursor::new(&b"123"[..]).chain(Cursor::new(&b"456789"[..])); + c.read_exact(&mut buf).unwrap(); + assert_eq!(&buf, b"1234"); + c.read_exact(&mut buf).unwrap(); + assert_eq!(&buf, b"5678"); + assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), + io::ErrorKind::UnexpectedEof); + } + + #[test] + fn read_exact_slice() { + let mut buf = [0; 4]; + + let mut c = &b""[..]; + assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), + io::ErrorKind::UnexpectedEof); + + let mut c = &b"123"[..]; + assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), + io::ErrorKind::UnexpectedEof); + // make sure the optimized (early returning) method is being used + assert_eq!(&buf, &[0; 4]); + + let mut c = &b"1234"[..]; + c.read_exact(&mut buf).unwrap(); + assert_eq!(&buf, b"1234"); + + let mut c = &b"56789"[..]; + c.read_exact(&mut buf).unwrap(); + assert_eq!(&buf, b"5678"); + assert_eq!(c, b"9"); + } + + #[test] + fn take_eof() { + struct R; + + impl Read for R { + fn read(&mut self, _: &mut [u8]) -> io::Result { + Err(io::Error::new(io::ErrorKind::Other, "")) + } + } + impl BufRead for R { + fn fill_buf(&mut self) -> io::Result<&[u8]> { + Err(io::Error::new(io::ErrorKind::Other, "")) + } + fn consume(&mut self, _amt: usize) { } + } + + let mut buf = [0; 1]; + assert_eq!(0, R.take(0).read(&mut buf).unwrap()); + assert_eq!(b"", R.take(0).fill_buf().unwrap()); + } + + fn cmp_bufread(mut br1: Br1, mut br2: Br2, exp: &[u8]) { + let mut cat = Vec::new(); + loop { + let consume = { + let buf1 = br1.fill_buf().unwrap(); + let buf2 = br2.fill_buf().unwrap(); + let minlen = if buf1.len() < buf2.len() { buf1.len() } else { buf2.len() }; + assert_eq!(buf1[..minlen], buf2[..minlen]); + cat.extend_from_slice(&buf1[..minlen]); + minlen + }; + if consume == 0 { + break; + } + br1.consume(consume); + br2.consume(consume); + } + assert_eq!(br1.fill_buf().unwrap().len(), 0); + assert_eq!(br2.fill_buf().unwrap().len(), 0); + assert_eq!(&cat[..], &exp[..]) + } + + #[test] + fn chain_bufread() { + let testdata = b"ABCDEFGHIJKL"; + let chain1 = (&testdata[..3]).chain(&testdata[3..6]) + .chain(&testdata[6..9]) + .chain(&testdata[9..]); + let chain2 = (&testdata[..4]).chain(&testdata[4..8]) + .chain(&testdata[8..]); + cmp_bufread(chain1, chain2, &testdata[..]); + } + + #[test] + fn chain_zero_length_read_is_not_eof() { + let a = b"A"; + let b = b"B"; + let mut s = String::new(); + let mut chain = (&a[..]).chain(&b[..]); + chain.read(&mut []).unwrap(); + chain.read_to_string(&mut s).unwrap(); + assert_eq!("AB", s); + } + + #[bench] + #[cfg_attr(target_os = "emscripten", ignore)] + fn bench_read_to_end(b: &mut test::Bencher) { + b.iter(|| { + let mut lr = repeat(1).take(10000000); + let mut vec = Vec::with_capacity(1024); + super::read_to_end(&mut lr, &mut vec) + }); + } +} diff --git a/ctr-std/src/io/prelude.rs b/ctr-std/src/io/prelude.rs new file mode 100644 index 0000000..8772d0f --- /dev/null +++ b/ctr-std/src/io/prelude.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. + +//! The I/O Prelude +//! +//! The purpose of this module is to alleviate imports of many common I/O traits +//! by adding a glob import to the top of I/O heavy modules: +//! +//! ``` +//! # #![allow(unused_imports)] +//! use std::io::prelude::*; +//! ``` + +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +pub use super::{Read, Write, BufRead, Seek}; diff --git a/ctr-std/src/io/print.rs b/ctr-std/src/io/print.rs new file mode 100644 index 0000000..8a5851b --- /dev/null +++ b/ctr-std/src/io/print.rs @@ -0,0 +1,33 @@ +use fmt; +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 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 { + // devkitPro's version of write(2) fails if zero bytes are written, + // so let's just exit if the buffer size is zero + if buf.is_empty() { + return Ok(buf.len()) + } + libc::write(libc::STDOUT_FILENO, buf.as_ptr() as *const _, buf.len()); + Ok(buf.len()) + } + } + + fn flush(&mut self) -> io::Result<()> { Ok(()) } +} + +#[doc(hidden)] +pub fn _print(args: fmt::Arguments) { + STDOUT.lock().write_fmt(args).unwrap(); +} diff --git a/ctr-std/src/io/util.rs b/ctr-std/src/io/util.rs new file mode 100644 index 0000000..2c68802 --- /dev/null +++ b/ctr-std/src/io/util.rs @@ -0,0 +1,215 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(missing_copy_implementations)] + +use io::{self, Read, Write, ErrorKind, BufRead}; + +/// Copies the entire contents of a reader into a writer. +/// +/// This function will continuously read data from `reader` and then +/// write it into `writer` in a streaming fashion until `reader` +/// returns EOF. +/// +/// On success, the total number of bytes that were copied from +/// `reader` to `writer` is returned. +/// +/// # Errors +/// +/// This function will return an error immediately if any call to `read` or +/// `write` returns an error. All instances of `ErrorKind::Interrupted` are +/// handled by this function and the underlying operation is retried. +/// +/// # Examples +/// +/// ``` +/// use std::io; +/// +/// # fn foo() -> io::Result<()> { +/// let mut reader: &[u8] = b"hello"; +/// let mut writer: Vec = vec![]; +/// +/// try!(io::copy(&mut reader, &mut writer)); +/// +/// assert_eq!(reader, &writer[..]); +/// # Ok(()) +/// # } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub fn copy(reader: &mut R, writer: &mut W) -> io::Result + where R: Read, W: Write +{ + let mut buf = [0; super::DEFAULT_BUF_SIZE]; + let mut written = 0; + loop { + let len = match reader.read(&mut buf) { + Ok(0) => return Ok(written), + Ok(len) => len, + Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, + Err(e) => return Err(e), + }; + writer.write_all(&buf[..len])?; + written += len as u64; + } +} + +/// A reader which is always at EOF. +/// +/// This struct is generally created by calling [`empty()`][empty]. Please see +/// 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. +/// +/// All reads from the returned reader will return `Ok(0)`. +/// +/// # Examples +/// +/// A slightly sad example of not reading anything into a buffer: +/// +/// ``` +/// use std::io::{self, Read}; +/// +/// let mut buffer = String::new(); +/// io::empty().read_to_string(&mut buffer).unwrap(); +/// assert!(buffer.is_empty()); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub fn empty() -> Empty { Empty { _priv: () } } + +#[stable(feature = "rust1", since = "1.0.0")] +impl Read for Empty { + 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) {} +} + +/// A reader which yields one byte over and over and over and over and over and... +/// +/// This struct is generally created by calling [`repeat()`][repeat]. Please +/// see the documentation of `repeat()` for more details. +/// +/// [repeat]: fn.repeat.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Repeat { byte: u8 } + +/// Creates an instance of a reader that infinitely repeats one byte. +/// +/// All reads from this reader will succeed by filling the specified buffer with +/// the given byte. +/// +/// # Examples +/// +/// ``` +/// use std::io::{self, Read}; +/// +/// let mut buffer = [0; 3]; +/// io::repeat(0b101).read_exact(&mut buffer).unwrap(); +/// assert_eq!(buffer, [0b101, 0b101, 0b101]); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub fn repeat(byte: u8) -> Repeat { Repeat { byte: byte } } + +#[stable(feature = "rust1", since = "1.0.0")] +impl Read for Repeat { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + for slot in &mut *buf { + *slot = self.byte; + } + Ok(buf.len()) + } +} + +/// A writer which will move data into the void. +/// +/// This struct is generally created by calling [`sink()`][sink]. Please +/// see the documentation of `sink()` for more details. +/// +/// [sink]: fn.sink.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Sink { _priv: () } + +/// Creates an instance of a writer which will successfully consume all data. +/// +/// All calls to `write` on the returned instance will return `Ok(buf.len())` +/// and the contents of the buffer will not be inspected. +/// +/// # Examples +/// +/// ```rust +/// use std::io::{self, Write}; +/// +/// let buffer = vec![1, 2, 3, 5, 8]; +/// let num_bytes = io::sink().write(&buffer).unwrap(); +/// assert_eq!(num_bytes, 5); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub fn sink() -> Sink { Sink { _priv: () } } + +#[stable(feature = "rust1", since = "1.0.0")] +impl Write for Sink { + fn write(&mut self, buf: &[u8]) -> io::Result { Ok(buf.len()) } + fn flush(&mut self) -> io::Result<()> { Ok(()) } +} + +#[cfg(test)] +mod tests { + use io::prelude::*; + use io::{copy, sink, empty, repeat}; + + #[test] + fn copy_copies() { + let mut r = repeat(0).take(4); + let mut w = sink(); + assert_eq!(copy(&mut r, &mut w).unwrap(), 4); + + let mut r = repeat(0).take(1 << 17); + assert_eq!(copy(&mut r as &mut Read, &mut w as &mut Write).unwrap(), 1 << 17); + } + + #[test] + fn sink_sinks() { + let mut s = sink(); + assert_eq!(s.write(&[]).unwrap(), 0); + assert_eq!(s.write(&[0]).unwrap(), 1); + assert_eq!(s.write(&[0; 1024]).unwrap(), 1024); + assert_eq!(s.by_ref().write(&[0; 1024]).unwrap(), 1024); + } + + #[test] + fn empty_reads() { + let mut e = empty(); + assert_eq!(e.read(&mut []).unwrap(), 0); + assert_eq!(e.read(&mut [0]).unwrap(), 0); + assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0); + assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0); + } + + #[test] + fn repeat_repeats() { + let mut r = repeat(4); + let mut b = [0; 1024]; + assert_eq!(r.read(&mut b).unwrap(), 1024); + assert!(b.iter().all(|b| *b == 4)); + } + + #[test] + fn take_some_bytes() { + assert_eq!(repeat(4).take(100).bytes().count(), 100); + assert_eq!(repeat(4).take(100).bytes().next().unwrap().unwrap(), 4); + assert_eq!(repeat(1).take(10).chain(repeat(2).take(10)).bytes().count(), 20); + } +} diff --git a/ctr-std/src/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/ctr-std/src/num.rs b/ctr-std/src/num.rs new file mode 100644 index 0000000..d1c2fc3 --- /dev/null +++ b/ctr-std/src/num.rs @@ -0,0 +1,293 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Additional functionality for numerics. +//! +//! This module provides some extra types that are useful when doing numerical +//! work. See the individual documentation for each piece for more information. + +#![stable(feature = "rust1", since = "1.0.0")] +#![allow(missing_docs)] + +#[stable(feature = "rust1", since = "1.0.0")] +#[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}; + +/// Helper function for testing numeric operations +#[cfg(test)] +pub fn test_num(ten: T, two: T) where + T: PartialEq + + Add + Sub + + Mul + Div + + Rem + fmt::Debug + + Copy +{ + assert_eq!(ten.add(two), ten + two); + assert_eq!(ten.sub(two), ten - two); + assert_eq!(ten.mul(two), ten * two); + assert_eq!(ten.div(two), ten / two); + assert_eq!(ten.rem(two), ten % two); +} + +#[cfg(test)] +mod tests { + use u8; + use u16; + use u32; + use u64; + use usize; + use ops::Mul; + + #[test] + fn test_saturating_add_uint() { + use usize::MAX; + assert_eq!(3_usize.saturating_add(5_usize), 8_usize); + assert_eq!(3_usize.saturating_add(MAX-1), MAX); + assert_eq!(MAX.saturating_add(MAX), MAX); + assert_eq!((MAX-2).saturating_add(1), MAX-1); + } + + #[test] + fn test_saturating_sub_uint() { + use usize::MAX; + assert_eq!(5_usize.saturating_sub(3_usize), 2_usize); + assert_eq!(3_usize.saturating_sub(5_usize), 0_usize); + assert_eq!(0_usize.saturating_sub(1_usize), 0_usize); + assert_eq!((MAX-1).saturating_sub(MAX), 0); + } + + #[test] + fn test_saturating_add_int() { + use isize::{MIN,MAX}; + assert_eq!(3i32.saturating_add(5), 8); + assert_eq!(3isize.saturating_add(MAX-1), MAX); + assert_eq!(MAX.saturating_add(MAX), MAX); + assert_eq!((MAX-2).saturating_add(1), MAX-1); + assert_eq!(3i32.saturating_add(-5), -2); + assert_eq!(MIN.saturating_add(-1), MIN); + assert_eq!((-2isize).saturating_add(-MAX), MIN); + } + + #[test] + fn test_saturating_sub_int() { + use isize::{MIN,MAX}; + assert_eq!(3i32.saturating_sub(5), -2); + assert_eq!(MIN.saturating_sub(1), MIN); + assert_eq!((-2isize).saturating_sub(MAX), MIN); + assert_eq!(3i32.saturating_sub(-5), 8); + assert_eq!(3isize.saturating_sub(-(MAX-1)), MAX); + assert_eq!(MAX.saturating_sub(-MAX), MAX); + assert_eq!((MAX-2).saturating_sub(-1), MAX-1); + } + + #[test] + fn test_checked_add() { + let five_less = usize::MAX - 5; + assert_eq!(five_less.checked_add(0), Some(usize::MAX - 5)); + assert_eq!(five_less.checked_add(1), Some(usize::MAX - 4)); + assert_eq!(five_less.checked_add(2), Some(usize::MAX - 3)); + assert_eq!(five_less.checked_add(3), Some(usize::MAX - 2)); + assert_eq!(five_less.checked_add(4), Some(usize::MAX - 1)); + assert_eq!(five_less.checked_add(5), Some(usize::MAX)); + assert_eq!(five_less.checked_add(6), None); + assert_eq!(five_less.checked_add(7), None); + } + + #[test] + fn test_checked_sub() { + assert_eq!(5_usize.checked_sub(0), Some(5)); + assert_eq!(5_usize.checked_sub(1), Some(4)); + assert_eq!(5_usize.checked_sub(2), Some(3)); + assert_eq!(5_usize.checked_sub(3), Some(2)); + assert_eq!(5_usize.checked_sub(4), Some(1)); + assert_eq!(5_usize.checked_sub(5), Some(0)); + assert_eq!(5_usize.checked_sub(6), None); + assert_eq!(5_usize.checked_sub(7), None); + } + + #[test] + fn test_checked_mul() { + let third = usize::MAX / 3; + assert_eq!(third.checked_mul(0), Some(0)); + assert_eq!(third.checked_mul(1), Some(third)); + assert_eq!(third.checked_mul(2), Some(third * 2)); + assert_eq!(third.checked_mul(3), Some(third * 3)); + assert_eq!(third.checked_mul(4), None); + } + + macro_rules! test_is_power_of_two { + ($test_name:ident, $T:ident) => ( + fn $test_name() { + #![test] + assert_eq!((0 as $T).is_power_of_two(), false); + assert_eq!((1 as $T).is_power_of_two(), true); + assert_eq!((2 as $T).is_power_of_two(), true); + assert_eq!((3 as $T).is_power_of_two(), false); + assert_eq!((4 as $T).is_power_of_two(), true); + assert_eq!((5 as $T).is_power_of_two(), false); + assert_eq!(($T::MAX / 2 + 1).is_power_of_two(), true); + } + ) + } + + test_is_power_of_two!{ test_is_power_of_two_u8, u8 } + test_is_power_of_two!{ test_is_power_of_two_u16, u16 } + test_is_power_of_two!{ test_is_power_of_two_u32, u32 } + test_is_power_of_two!{ test_is_power_of_two_u64, u64 } + test_is_power_of_two!{ test_is_power_of_two_uint, usize } + + macro_rules! test_next_power_of_two { + ($test_name:ident, $T:ident) => ( + fn $test_name() { + #![test] + assert_eq!((0 as $T).next_power_of_two(), 1); + let mut next_power = 1; + for i in 1 as $T..40 { + assert_eq!(i.next_power_of_two(), next_power); + if i == next_power { next_power *= 2 } + } + } + ) + } + + test_next_power_of_two! { test_next_power_of_two_u8, u8 } + test_next_power_of_two! { test_next_power_of_two_u16, u16 } + test_next_power_of_two! { test_next_power_of_two_u32, u32 } + test_next_power_of_two! { test_next_power_of_two_u64, u64 } + test_next_power_of_two! { test_next_power_of_two_uint, usize } + + macro_rules! test_checked_next_power_of_two { + ($test_name:ident, $T:ident) => ( + fn $test_name() { + #![test] + assert_eq!((0 as $T).checked_next_power_of_two(), Some(1)); + assert!(($T::MAX / 2).checked_next_power_of_two().is_some()); + assert_eq!(($T::MAX - 1).checked_next_power_of_two(), None); + assert_eq!($T::MAX.checked_next_power_of_two(), None); + let mut next_power = 1; + for i in 1 as $T..40 { + assert_eq!(i.checked_next_power_of_two(), Some(next_power)); + if i == next_power { next_power *= 2 } + } + } + ) + } + + test_checked_next_power_of_two! { test_checked_next_power_of_two_u8, u8 } + test_checked_next_power_of_two! { test_checked_next_power_of_two_u16, u16 } + test_checked_next_power_of_two! { test_checked_next_power_of_two_u32, u32 } + test_checked_next_power_of_two! { test_checked_next_power_of_two_u64, u64 } + test_checked_next_power_of_two! { test_checked_next_power_of_two_uint, usize } + + #[test] + fn test_pow() { + fn naive_pow + Copy>(one: T, base: T, exp: usize) -> T { + (0..exp).fold(one, |acc, _| acc * base) + } + macro_rules! assert_pow { + (($num:expr, $exp:expr) => $expected:expr) => {{ + let result = $num.pow($exp); + assert_eq!(result, $expected); + assert_eq!(result, naive_pow(1, $num, $exp)); + }} + } + assert_pow!((3u32, 0 ) => 1); + assert_pow!((5u32, 1 ) => 5); + assert_pow!((-4i32, 2 ) => 16); + assert_pow!((8u32, 3 ) => 512); + assert_pow!((2u64, 50) => 1125899906842624); + } + + #[test] + fn test_uint_to_str_overflow() { + let mut u8_val: u8 = 255; + assert_eq!(u8_val.to_string(), "255"); + + u8_val = u8_val.wrapping_add(1); + assert_eq!(u8_val.to_string(), "0"); + + let mut u16_val: u16 = 65_535; + assert_eq!(u16_val.to_string(), "65535"); + + u16_val = u16_val.wrapping_add(1); + assert_eq!(u16_val.to_string(), "0"); + + let mut u32_val: u32 = 4_294_967_295; + assert_eq!(u32_val.to_string(), "4294967295"); + + u32_val = u32_val.wrapping_add(1); + assert_eq!(u32_val.to_string(), "0"); + + let mut u64_val: u64 = 18_446_744_073_709_551_615; + assert_eq!(u64_val.to_string(), "18446744073709551615"); + + u64_val = u64_val.wrapping_add(1); + assert_eq!(u64_val.to_string(), "0"); + } + + fn from_str(t: &str) -> Option { + ::str::FromStr::from_str(t).ok() + } + + #[test] + fn test_uint_from_str_overflow() { + let mut u8_val: u8 = 255; + assert_eq!(from_str::("255"), Some(u8_val)); + assert_eq!(from_str::("256"), None); + + u8_val = u8_val.wrapping_add(1); + assert_eq!(from_str::("0"), Some(u8_val)); + assert_eq!(from_str::("-1"), None); + + let mut u16_val: u16 = 65_535; + assert_eq!(from_str::("65535"), Some(u16_val)); + assert_eq!(from_str::("65536"), None); + + u16_val = u16_val.wrapping_add(1); + assert_eq!(from_str::("0"), Some(u16_val)); + assert_eq!(from_str::("-1"), None); + + let mut u32_val: u32 = 4_294_967_295; + assert_eq!(from_str::("4294967295"), Some(u32_val)); + assert_eq!(from_str::("4294967296"), None); + + u32_val = u32_val.wrapping_add(1); + assert_eq!(from_str::("0"), Some(u32_val)); + assert_eq!(from_str::("-1"), None); + + let mut u64_val: u64 = 18_446_744_073_709_551_615; + assert_eq!(from_str::("18446744073709551615"), Some(u64_val)); + assert_eq!(from_str::("18446744073709551616"), None); + + u64_val = u64_val.wrapping_add(1); + assert_eq!(from_str::("0"), Some(u64_val)); + assert_eq!(from_str::("-1"), None); + } +} + + +#[cfg(test)] +mod bench { + extern crate test; + use self::test::Bencher; + + #[bench] + fn bench_pow_function(b: &mut Bencher) { + let v = (0..1024).collect::>(); + b.iter(|| {v.iter().fold(0u32, |old, new| old.pow(*new as u32));}); + } +} diff --git a/ctr-std/src/os/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/src/panic.rs b/ctr-std/src/panicking.rs similarity index 68% rename from src/panic.rs rename to ctr-std/src/panicking.rs index 9fb3e82..d6b922d 100644 --- a/src/panic.rs +++ b/ctr-std/src/panicking.rs @@ -11,11 +11,9 @@ //! Implementation of various bits and pieces of the `panic!` macro and //! associated runtime pieces. -use core::fmt::{self, Display, Write}; -use core::any::Any; - -use collections::String; -use collections::boxed::Box; +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"] @@ -23,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)) } @@ -33,9 +31,13 @@ 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; + let mut s = String::new(); let _ = s.write_fmt(*msg); begin_panic(s, file_line); @@ -45,21 +47,13 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments, file_line: &(&'static str, u32)) -> #[inline(never)] #[cold] pub fn begin_panic(msg: M, file_line: &(&'static str, u32)) -> ! { - use gfx::Screen; - use console::Console; - let msg = Box::new(msg); let (file, line) = *file_line; - let mut error_top = Console::init(Screen::Top); - let mut error_bottom = Console::init(Screen::Bottom); - - write!(error_top, "--------------------------------------------------").unwrap(); - writeln!(error_top, "PANIC in {} at line {}:", file, line).unwrap(); - writeln!(error_top, " {}", msg).unwrap(); - write!(error_top, "\x1b[29;00H--------------------------------------------------").unwrap(); - - write!(error_bottom, "").unwrap(); + print!("--------------------------------------------------"); + println!("PANIC in {} at line {}:", file, line); + println!(" {}", msg); + print!("\x1b[29;00H--------------------------------------------------"); loop {} } diff --git a/src/path.rs b/ctr-std/src/path.rs similarity index 85% rename from src/path.rs rename to ctr-std/src/path.rs index 3fb6357..92c561f 100644 --- a/src/path.rs +++ b/ctr-std/src/path.rs @@ -97,23 +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 collections::borrow::{Borrow, ToOwned, Cow}; -use core::cmp; -//use error::Error; -use core::fmt; +use borrow::{Borrow, Cow}; +use cmp; +use error::Error; +use fmt; //use fs; -use core::hash::{Hash, Hasher}; +use hash::{Hash, Hasher}; //use io; -use core::iter; -use core::mem; -use core::ops::{self, Deref}; -use collections::String; -use collections::Vec; +use iter::{self, FusedIterator}; +use mem; +use ops::{self, Deref}; 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 @@ -125,130 +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. - -#[cfg(unix)] -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 = '/'; -} - -#[cfg(windows)] -mod platform { - use ascii::*; - - use super::{os_str_as_u8_slice, u8_slice_as_os_str, Prefix}; - use ffi::OsStr; - - #[inline] - pub fn is_sep_byte(b: u8) -> bool { - b == b'/' || b == b'\\' - } - - #[inline] - pub fn is_verbatim_sep(b: u8) -> bool { - b == b'\\' - } - - pub fn parse_prefix<'a>(path: &'a OsStr) -> Option { - use super::Prefix::*; - unsafe { - // The unsafety here stems from converting between &OsStr and &[u8] - // and back. This is safe to do because (1) we only look at ASCII - // contents of the encoding and (2) new &OsStr values are produced - // only from ASCII-bounded slices of existing &OsStr values. - let mut path = os_str_as_u8_slice(path); - - if path.starts_with(br"\\") { - // \\ - path = &path[2..]; - if path.starts_with(br"?\") { - // \\?\ - path = &path[2..]; - if path.starts_with(br"UNC\") { - // \\?\UNC\server\share - path = &path[4..]; - let (server, share) = match parse_two_comps(path, is_verbatim_sep) { - Some((server, share)) => - (u8_slice_as_os_str(server), u8_slice_as_os_str(share)), - None => (u8_slice_as_os_str(path), u8_slice_as_os_str(&[])), - }; - return Some(VerbatimUNC(server, share)); - } else { - // \\?\path - let idx = path.iter().position(|&b| b == b'\\'); - if idx == Some(2) && path[1] == b':' { - let c = path[0]; - if c.is_ascii() && (c as char).is_alphabetic() { - // \\?\C:\ path - return Some(VerbatimDisk(c.to_ascii_uppercase())); - } - } - let slice = &path[..idx.unwrap_or(path.len())]; - return Some(Verbatim(u8_slice_as_os_str(slice))); - } - } else if path.starts_with(b".\\") { - // \\.\path - path = &path[2..]; - let pos = path.iter().position(|&b| b == b'\\'); - let slice = &path[..pos.unwrap_or(path.len())]; - return Some(DeviceNS(u8_slice_as_os_str(slice))); - } - match parse_two_comps(path, is_sep_byte) { - Some((server, share)) if !server.is_empty() && !share.is_empty() => { - // \\server\share - return Some(UNC(u8_slice_as_os_str(server), u8_slice_as_os_str(share))); - } - _ => (), - } - } else if path.get(1) == Some(& b':') { - // C: - let c = path[0]; - if c.is_ascii() && (c as char).is_alphabetic() { - return Some(Disk(c.to_ascii_uppercase())); - } - } - return None; - } - - fn parse_two_comps(mut path: &[u8], f: fn(u8) -> bool) -> Option<(&[u8], &[u8])> { - let first = match path.iter().position(|x| f(*x)) { - None => return None, - Some(x) => &path[..x], - }; - path = &path[(first.len() + 1)..]; - let idx = path.iter().position(|x| f(*x)); - let second = &path[..idx.unwrap_or(path.len())]; - Some((first, second)) - } - } - - pub const MAIN_SEP_STR: &'static str = "\\"; - pub const MAIN_SEP: char = '\\'; -} - //////////////////////////////////////////////////////////////////////////////// // Windows Prefixes //////////////////////////////////////////////////////////////////////////////// @@ -261,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> { @@ -320,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, } } @@ -357,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 @@ -456,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. @@ -467,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); @@ -526,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(), @@ -560,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() @@ -587,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], @@ -607,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] @@ -677,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 { @@ -775,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; @@ -814,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>; @@ -872,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() { @@ -918,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()) @@ -942,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. @@ -962,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, } @@ -972,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 } @@ -1005,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()) } @@ -1039,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) => { @@ -1053,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 /// /// ``` @@ -1071,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()) } @@ -1083,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()) } @@ -1112,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(); @@ -1144,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 { @@ -1152,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; @@ -1166,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> { @@ -1179,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> { @@ -1186,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 { @@ -1193,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 /// @@ -1253,6 +1319,7 @@ impl Into for PathBuf { /// let parent_dir = path.parent(); /// ``` /// +#[stable(feature = "rust1", since = "1.0.0")] pub struct Path { inner: OsStr, } @@ -1260,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 { @@ -1295,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 /// @@ -1309,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 /// /// ``` @@ -1325,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 /// /// ``` @@ -1341,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 /// @@ -1355,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()) } @@ -1374,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()) @@ -1388,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() } @@ -1412,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() } @@ -1433,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(); @@ -1472,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 { @@ -1487,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 @@ -1516,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()) } @@ -1537,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()) } @@ -1545,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: /// @@ -1563,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: /// @@ -1585,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 /// @@ -1600,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()) } @@ -1610,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 /// @@ -1622,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()) } @@ -1632,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 /// @@ -1644,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()) } @@ -1669,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 { @@ -1680,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 /// @@ -1694,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 /// /// ``` @@ -1710,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 @@ -1728,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) } @@ -1737,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 @@ -1791,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 @@ -1809,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 @@ -1827,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) @@ -1847,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() { @@ -1877,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>; @@ -1947,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 { @@ -1964,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 { @@ -1981,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 { @@ -1998,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 { @@ -2022,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) => ( @@ -2128,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(); @@ -3228,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(); @@ -3253,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() } @@ -3375,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/ctr-std/src/rt.rs b/ctr-std/src/rt.rs new file mode 100644 index 0000000..178b5a0 --- /dev/null +++ b/ctr-std/src/rt.rs @@ -0,0 +1,36 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Runtime services +//! +//! The `rt` module provides a narrow set of runtime services, +//! including the global heap (exported in `heap`) and unwinding and +//! backtrace support. The APIs in this module are highly unstable, +//! and should be considered as private implementation details for the +//! time being. + +#![unstable(feature = "rt", + reason = "this public module should not exist and is highly likely \ + to disappear", + issue = "0")] +#![doc(hidden)] + +use mem; + +// Reexport some of our utilities which are expected by other crates. +pub use panicking::{begin_panic, begin_panic_fmt}; + +//TODO: Handle argc/argv arguments +#[lang = "start"] +#[allow(unused_variables)] +fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize { + unsafe { mem::transmute::<_, fn()>(main)(); } + 0 +} 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-rs/3ds.json b/ctru-rs/3ds.json new file mode 100644 index 0000000..bdd5caa --- /dev/null +++ b/ctru-rs/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/Cargo.toml b/ctru-rs/Cargo.toml similarity index 63% rename from Cargo.toml rename to ctru-rs/Cargo.toml index f95ca35..cf43e1b 100644 --- a/Cargo.toml +++ b/ctru-rs/Cargo.toml @@ -1,18 +1,19 @@ [package] authors = ["Ronald Kinard "] -build = "build.rs" description = "A safe wrapper around smealum's ctrulib." license = "https://en.wikipedia.org/wiki/Zlib_License" -links = "ctru" name = "ctru-rs" -version = "0.4.0" - -[dependencies.ctru-sys] -path = "ctru-sys" - -[dependencies.alloc_system3ds] -git = "https://github.com/rust3ds/alloc_system3ds" +version = "0.5.0" [lib] crate-type = ["rlib"] name = "ctru" + +[dependencies.ctru-sys] +path = "../ctru-sys" + +[dependencies.bitflags] +version = "0.7.0" + +[dependencies.widestring] +version = "0.2.2" diff --git a/ctru-rs/README.md b/ctru-rs/README.md new file mode 100644 index 0000000..215b574 --- /dev/null +++ b/ctru-rs/README.md @@ -0,0 +1,44 @@ +# ctru-rs + +A Rust wrapper library for smealum's +[ctrulib](https://github.com/smealum/ctrulib). + +See the [3DS project template](https://github.com/rust3ds/rust3ds-template) for instructions on how to use this library. + +## Structure + +This library is meant to expose 3DS-specific functionality. Common functionality is implemented in `ctr-std` when possible. + +## Contributing + +PR's are welcome. Organization of rust specific features and wrapper functionality are still being decided on. + +## License + +Copyright (C) Rust 3DS Project authors, 2015-2016 + +See AUTHORS.md. + +As with the original ctrulib, this library is licensed under zlib. This +applies to every file in the tree, unless otherwise noted. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + 3. This notice may not be removed or altered from any source + distribution. + +Rust is primarily distributed under the terms of both the MIT license and the Apache License (Version 2.0), with portions covered by various BSD-like licenses. + +See [LICENSE-APACHE](https://github.com/rust-lang/rust/blob/master/LICENSE-APACHE), [LICENSE-MIT](https://github.com/rust-lang/rust/blob/master/LICENSE-MIT), and [COPYRIGHT](https://github.com/rust-lang/rust/blob/master/COPYRIGHT) for details. diff --git a/ctru-rs/Xargo.toml b/ctru-rs/Xargo.toml new file mode 100644 index 0000000..43d0173 --- /dev/null +++ b/ctru-rs/Xargo.toml @@ -0,0 +1,9 @@ +[dependencies.collections] + +[dependencies.ctr-libc] +path = "../ctr-libc" +stage = 1 + +[dependencies.std] +path = "../ctr-std" +stage = 2 diff --git a/ctru-rs/src/console.rs b/ctru-rs/src/console.rs new file mode 100644 index 0000000..3284d00 --- /dev/null +++ b/ctru-rs/src/console.rs @@ -0,0 +1,37 @@ +use std::default::Default; +use std::ptr; + +use gfx::Screen; + +use libctru::console::*; + +pub struct Console { + context: PrintConsole, +} + +impl Console { + pub fn init(screen: Screen) -> Self { + unsafe { + let ret = *(consoleInit(screen.into(), ptr::null_mut())); + Console { context: ret } + } + } + + pub fn select(&mut self) { + unsafe { consoleSelect(&mut self.context); } + } + + pub fn set_window(&mut self, x: i32, y: i32, width: i32, height: i32) { + unsafe { consoleSetWindow(&mut self.context, x, y, width, height) } + } + + pub fn clear(&mut self) { + unsafe { consoleClear() } + } +} + +impl Default for Console { + fn default() -> Self { + Console::init(Screen::Top) + } +} diff --git a/ctru-rs/src/error.rs b/ctru-rs/src/error.rs new file mode 100644 index 0000000..b1d968b --- /dev/null +++ b/ctru-rs/src/error.rs @@ -0,0 +1,38 @@ +use std::error; +use std::fmt; + +pub type Result = ::std::result::Result; + +/// The error type returned by all libctru functions. +pub enum Error { + Os(i32), +} + +impl From for Error { + fn from(err: i32) -> Self { + Error::Os(err) + } +} + +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Error::Os(err) => write!(f, "libctru result code: {:08X}", err), + } + } +} + +// TODO: Expand libctru result code into human-readable error message +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Error::Os(err) => write!(f, "libctru result code: 0x{:08X}", err), + } + } +} + +impl error::Error for Error { + fn description(&self) -> &str { + "error originating from a libctru function" + } +} diff --git a/src/gfx.rs b/ctru-rs/src/gfx.rs similarity index 93% rename from src/gfx.rs rename to ctru-rs/src/gfx.rs index 7504632..7f819ea 100644 --- a/src/gfx.rs +++ b/ctru-rs/src/gfx.rs @@ -1,8 +1,8 @@ use libctru::gfx; -use core::default::Default; -use core::marker::PhantomData; -use core::ops::Drop; +use std::default::Default; +use std::marker::PhantomData; +use std::ops::Drop; use services::gspgpu::FramebufferFormat; @@ -82,9 +82,9 @@ impl Gfx { } pub fn get_framebuffer(&mut self, screen: Screen, side: Side) -> (&'static mut [u8], u16, u16) { - use core::convert::Into; + use std::convert::Into; unsafe { - use core::slice::from_raw_parts_mut; + use std::slice::from_raw_parts_mut; let mut w: u16 = 0; let mut h: u16 = 0; @@ -112,12 +112,12 @@ impl Gfx { } pub fn get_framebuffer_format(&self, screen: Screen) -> FramebufferFormat { - use core::convert::Into; + use std::convert::Into; unsafe { gfx::gfxGetScreenFormat(screen.into()).into() } } pub fn set_framebuffer_format(&mut self, screen: Screen, fmt: FramebufferFormat) { - use core::convert::Into; + use std::convert::Into; unsafe { gfx::gfxSetScreenFormat(screen.into(), fmt.into()) } } diff --git a/ctru-rs/src/lib.rs b/ctru-rs/src/lib.rs new file mode 100644 index 0000000..10132a0 --- /dev/null +++ b/ctru-rs/src/lib.rs @@ -0,0 +1,21 @@ +#![crate_type = "rlib"] +#![crate_name = "ctru"] + +#[macro_use] +extern crate bitflags; +extern crate widestring; + +extern crate ctru_sys as libctru; + +pub mod console; +pub mod error; +pub mod srv; +pub mod gfx; +pub mod services; +pub mod sdmc; + +pub use error::{Result, Error}; + +pub use srv::Srv; +pub use gfx::Gfx; +pub use sdmc::Sdmc; diff --git a/src/sdmc.rs b/ctru-rs/src/sdmc.rs similarity index 76% rename from src/sdmc.rs rename to ctru-rs/src/sdmc.rs index 75a58a9..6196394 100644 --- a/src/sdmc.rs +++ b/ctru-rs/src/sdmc.rs @@ -1,4 +1,4 @@ -use core::marker::PhantomData; +use std::marker::PhantomData; use libctru::sdmc::*; @@ -7,11 +7,11 @@ pub struct Sdmc { } impl Sdmc { - pub fn init() -> Result { + pub fn init() -> ::Result { unsafe { let r = sdmcInit(); if r < 0 { - Err(r) + Err(::Error::from(r)) } else { Ok(Sdmc { pd: PhantomData }) } diff --git a/ctru-rs/src/services/apt.rs b/ctru-rs/src/services/apt.rs new file mode 100644 index 0000000..0c8e281 --- /dev/null +++ b/ctru-rs/src/services/apt.rs @@ -0,0 +1,36 @@ +use std::marker::PhantomData; + +use libctru::services::apt; + +pub struct Apt { + pd: PhantomData +} + +impl Apt { + pub fn init() -> ::Result { + unsafe { + let r = apt::aptInit(); + if r < 0 { + Err(::Error::from(r)) + } else { + Ok(Apt { pd: PhantomData }) + } + } + } + + pub fn main_loop(&self) -> bool { + unsafe { + match apt::aptMainLoop() { + 1 => true, + 0 => false, + _ => unreachable!(), + } + } + } +} + +impl Drop for Apt { + fn drop(&mut self) { + unsafe { apt::aptExit() }; + } +} diff --git a/src/services/fs.rs b/ctru-rs/src/services/fs.rs similarity index 76% rename from src/services/fs.rs rename to ctru-rs/src/services/fs.rs index d4aedc4..2a567e2 100644 --- a/src/services/fs.rs +++ b/ctru-rs/src/services/fs.rs @@ -3,19 +3,47 @@ //! This module contains basic methods to manipulate the contents of the 3DS's filesystem. //! Only the SD card is currently supported. +use std::io::{Read, Write, Seek, SeekFrom}; +use std::io::Error as IoError; +use std::io::Result as IoResult; +use std::io::ErrorKind as IoErrorKind; -use core::marker::PhantomData; -use core::ptr; -use core::slice; -use core::mem; -use alloc::arc::Arc; -use collections::Vec; +use std::ffi::OsString; +use std::marker::PhantomData; +use std::ptr; +use std::slice; +use std::mem; +use std::path::{Path, PathBuf}; +use std::sync::Arc; -use path::{Path, PathBuf}; -use ffi::OsString; +use widestring::{WideCString, WideCStr}; use libctru::services::fs::*; +bitflags! { + flags FsOpen: u32 { + const FS_OPEN_READ = 1, + const FS_OPEN_WRITE = 2, + const FS_OPEN_CREATE = 4, + } +} + +bitflags! { + flags FsWrite: u32 { + const FS_WRITE_FLUSH = 1, + const FS_WRITE_UPDATE_TIME = 256, + } +} + +bitflags! { + flags FsAttribute: u32 { + const FS_ATTRIBUTE_DIRECTORY = 1, + const FS_ATTRIBUTE_HIDDEN = 256, + const FS_ATTRIBUTE_ARCHIVE = 65536, + const FS_ATTRIBUTE_READ_ONLY = 16777216, + } +} + #[derive(Copy, Clone, Debug)] pub enum PathType { Invalid, @@ -82,6 +110,63 @@ pub struct Archive { /// on what options It was opened with. /// /// Files are automatically closed when they go out of scope. +/// +/// # Examples +/// +/// Create a new file and write bytes to it: +/// +/// ```no_run +/// use std::io::prelude::*; +/// use ctru::services::fs::{Fs, File}; +/// +/// # fn foo() -> std::io::Result<()> { +/// let fs = Fs::init()?; +/// let sdmc = fs.sdmc()?; +/// +/// let mut file = File::create(&sdmc, "/foo.txt")?; +/// file.write_all(b"Hello, world!")?; +/// # Ok(()) +/// #} +/// ``` +/// +/// Read the contents of a file into a `String`:: +/// +/// ```no_run +/// use std::io::prelude::*; +/// use ctru::services::fs::{Fs, File}; +/// +/// # fn foo() -> std::io::Result<()> { +/// let fs = Fs::init()?; +/// let sdmc = fs.sdmc()?; +/// +/// let mut file = File::open(&sdmc, "/foo.txt")?; +/// let mut contents = String::new(); +/// file.read_to_string(&mut contents)?; +/// assert_eq!(contents, "Hello, world!"); +/// # Ok(()) +/// #} +/// ``` +/// +/// It can be more efficient to read the contents of a file with a buffered +/// `Read`er. This can be accomplished with `BufReader`: +/// +/// ```no_run +/// use std::io::BufReader; +/// use std::io::prelude::*; +/// use ctru::services::fs::{Fs, File}; +/// +/// # fn foo() -> std::io::Result<()> { +/// let fs = Fs::init()?; +/// let sdmc = fs.sdmc()?; +/// +/// let file = File::open(&sdmc, "/foo.txt")?; +/// let mut buf_reader = BufReader::new(file); +/// let mut contents = String::new(); +/// buf_reader.read_to_string(&mut contents)?; +/// assert_eq!(contents, "Hello, world!"); +/// # Ok(()) +/// # } +/// ``` pub struct File { handle: u32, offset: u64, @@ -215,11 +300,11 @@ impl Fs { /// ctrulib services are reference counted, so this function may be called /// as many times as desired and the service will not exit until all /// instances of Fs drop out of scope. - pub fn init() -> Result { + pub fn init() -> ::Result { unsafe { let r = fsInit(); if r < 0 { - Err(r) + Err(::Error::from(r)) } else { Ok(Fs { pd: PhantomData }) } @@ -227,14 +312,14 @@ impl Fs { } /// Returns a handle to the SDMC (memory card) Archive. - pub fn sdmc(&self) -> Result { + pub fn sdmc(&self) -> ::Result { unsafe { let mut handle = 0; let id = ArchiveID::Sdmc; let path = fsMakePath(PathType::Empty.into(), ptr::null() as _); let r = FSUSER_OpenArchive(&mut handle, id.into(), path); if r < 0 { - Err(r) + Err(::Error::from(r)) } else { Ok(Archive { handle: handle, @@ -275,7 +360,7 @@ impl File { /// let sdmc_archive = fs.sdmc().unwrap() /// let mut f = File::open(&sdmc_archive, "/foo.txt").unwrap(); /// ``` - pub fn open>(arch: &Archive, path: P) -> Result { + pub fn open>(arch: &Archive, path: P) -> IoResult { OpenOptions::new().read(true).archive(arch).open(path.as_ref()) } @@ -301,7 +386,7 @@ impl File { /// let sdmc_archive = fs.sdmc().unwrap() /// let mut f = File::create(&sdmc_archive, "/foo.txt").unwrap(); /// ``` - pub fn create>(arch: &Archive, path: P) -> Result { + pub fn create>(arch: &Archive, path: P) -> IoResult { OpenOptions::new().write(true).create(true).archive(arch).open(path.as_ref()) } @@ -310,11 +395,15 @@ impl File { /// If the size is less than the current file's size, then the file will be shrunk. If it is /// greater than the current file's size, then the file will be extended to size and have all /// of the intermediate data filled in with 0s. - pub fn set_len(&mut self, size: u64) -> Result<(), i32> { + /// + /// # Errors + /// + /// This function will return an error if the file is not opened for writing. + pub fn set_len(&mut self, size: u64) -> IoResult<()> { unsafe { let r = FSFILE_SetSize(self.handle, size); if r < 0 { - Err(r) + Err(IoError::new(IoErrorKind::PermissionDenied, ::Error::from(r))) } else { Ok(()) } @@ -322,26 +411,21 @@ impl File { } /// Queries metadata about the underlying file. - pub fn metadata(&self) -> Result { + pub fn metadata(&self) -> IoResult { // The only metadata we have for files right now is file size. // This is likely to change in the future. unsafe { let mut size = 0; let r = FSFILE_GetSize(self.handle, &mut size); if r < 0 { - Err(r) + Err(IoError::new(IoErrorKind::PermissionDenied, ::Error::from(r))) } else { Ok(Metadata { attributes: 0, size: size }) } } } - /// Pull some bytes from the file into the specified buffer, returning - /// how many bytes were read. - /// - /// This function will become private when std::io support is ported - /// to this library. - pub fn read(&mut self, buf: &mut [u8]) -> Result { + fn read(&mut self, buf: &mut [u8]) -> IoResult { unsafe { let mut n_read = 0; let r = FSFILE_Read( @@ -353,28 +437,18 @@ impl File { ); self.offset += n_read as u64; if r < 0 { - Err(r) + Err(IoError::new(IoErrorKind::Other, ::Error::from(r))) } else { Ok(n_read as usize) } } } - /// Read all bytes until EOF in this source, placing them into buf. - /// - /// This function will become private when std::io support is ported - /// to this library. - pub fn read_to_end(&mut self, buf: &mut Vec) -> Result { - unsafe { - read_to_end_uninitialized(self, buf) - } + fn read_to_end(&mut self, buf: &mut Vec) -> IoResult { + unsafe { read_to_end_uninitialized(self, buf) } } - /// Write a buffer into this object, returning how many bytes were written. - /// - /// This function will become private when std::io support is ported - /// to this library. - pub fn write(&mut self, buf: &[u8]) -> Result { + fn write(&mut self, buf: &[u8]) -> IoResult { unsafe { let mut n_written = 0; let r = FSFILE_Write( @@ -383,11 +457,11 @@ impl File { self.offset, buf.as_ptr() as _, buf.len() as u32, - FS_WRITE_UPDATE_TIME + FS_WRITE_UPDATE_TIME.bits() ); self.offset += n_written as u64; if r < 0 { - Err(r) + Err(IoError::new(IoErrorKind::Other, ::Error::from(r))) } else { Ok(n_written as usize) } @@ -398,7 +472,7 @@ impl File { impl Metadata { /// Returns whether this metadata is for a directory. pub fn is_dir(&self) -> bool { - self.attributes == self.attributes | FS_ATTRIBUTE_DIRECTORY + self.attributes == self.attributes | FS_ATTRIBUTE_DIRECTORY.bits } /// Returns whether this metadata is for a regular file. @@ -507,38 +581,38 @@ impl OpenOptions { /// * Invalid combinations of open options. /// /// [`Archive`]: struct.Archive.html - pub fn open>(&self, path: P) -> Result { + pub fn open>(&self, path: P) -> IoResult { self._open(path.as_ref(), self.get_open_flags()) } - fn _open(&self, path: &Path, flags: u32) -> Result { + fn _open(&self, path: &Path, flags: FsOpen) -> IoResult { unsafe { let mut file_handle = 0; let path = to_utf16(path); let fs_path = fsMakePath(PathType::UTF16.into(), path.as_ptr() as _); - let r = FSUSER_OpenFile(&mut file_handle, self.arch_handle, fs_path, flags, 0); + let r = FSUSER_OpenFile(&mut file_handle, self.arch_handle, fs_path, flags.bits, 0); if r < 0 { - return Err(r); + return Err(IoError::new(IoErrorKind::Other, ::Error::from(r))); } let mut file = File { handle: file_handle, offset: 0 }; if self.append { - let metadata = try!(file.metadata()); + let metadata = file.metadata()?; file.offset = metadata.len(); } // set the offset to 0 just in case both append and truncate were // set to true if self.truncate { - try!(file.set_len(0)); + file.set_len(0)?; file.offset = 0; } Ok(file) } } - fn get_open_flags(&self) -> u32 { + fn get_open_flags(&self) -> FsOpen { match (self.read, self.write || self.append, self.create) { (true, false, false) => FS_OPEN_READ, (false, true, false) => FS_OPEN_WRITE, @@ -546,15 +620,15 @@ impl OpenOptions { (true, false, true) => FS_OPEN_READ | FS_OPEN_CREATE, (true, true, false) => FS_OPEN_READ | FS_OPEN_WRITE, (true, true, true) => FS_OPEN_READ | FS_OPEN_WRITE | FS_OPEN_CREATE, - _ => 0, //failure case + _ => FsOpen::empty(), //failure case } } } impl<'a> Iterator for ReadDir<'a> { - type Item = Result, i32>; + type Item = IoResult>; - fn next(&mut self) -> Option, i32>> { + fn next(&mut self) -> Option>> { unsafe { let mut ret = DirEntry { entry: mem::zeroed(), @@ -566,7 +640,7 @@ impl<'a> Iterator for ReadDir<'a> { let r = FSDIR_Read(self.handle.0, &mut entries_read, entry_count, &mut ret.entry); if r < 0 { - return Some(Err(r)) + return Some(Err(IoError::new(IoErrorKind::Other, ::Error::from(r)))) } if entries_read != entry_count { return None @@ -586,15 +660,18 @@ impl<'a> DirEntry<'a> { } /// Return the metadata for the file that this entry points at. - pub fn metadata(&self) -> Result { + pub fn metadata(&self) -> IoResult { metadata(self.arch, self.path()) } /// 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() + } } } @@ -606,13 +683,13 @@ impl<'a> DirEntry<'a> { /// but is not limited to just these cases: /// /// * User lacks permissions to create directory at `path` -pub fn create_dir>(arch: &Archive, path: P) -> Result<(), i32> { +pub fn create_dir>(arch: &Archive, path: P) -> IoResult<()> { unsafe { let path = to_utf16(path.as_ref()); let fs_path = fsMakePath(PathType::UTF16.into(), path.as_ptr() as _); - let r = FSUSER_CreateDirectory(arch.handle, fs_path, FS_ATTRIBUTE_DIRECTORY); + let r = FSUSER_CreateDirectory(arch.handle, fs_path, FS_ATTRIBUTE_DIRECTORY.bits); if r < 0 { - Err(r) + Err(IoError::new(IoErrorKind::Other, ::Error::from(r))) } else { Ok(()) } @@ -628,7 +705,7 @@ pub fn create_dir>(arch: &Archive, path: P) -> Result<(), i32> { /// /// * If any directory in the path specified by `path` does not already exist /// and it could not be created otherwise. -pub fn create_dir_all>(arch: &Archive, path: P) -> Result<(), i32> { +pub fn create_dir_all>(arch: &Archive, path: P) -> IoResult<()> { let path = path.as_ref(); let mut dir = PathBuf::new(); let mut result = Ok(()); @@ -642,13 +719,13 @@ pub fn create_dir_all>(arch: &Archive, path: P) -> Result<(), i32 } /// Given a path, query the file system to get information about a file, directory, etc -pub fn metadata>(arch: &Archive, path: P) -> Result { +pub fn metadata>(arch: &Archive, path: P) -> IoResult { let maybe_file = File::open(&arch, path.as_ref()); let maybe_dir = read_dir(&arch, path.as_ref()); match (maybe_file, maybe_dir) { (Ok(file), _) => file.metadata(), - (_, Ok(_dir)) => Ok(Metadata { attributes: FS_ATTRIBUTE_DIRECTORY, size: 0 }), - (Err(r), _) => Err(r), + (_, Ok(_dir)) => Ok(Metadata { attributes: FS_ATTRIBUTE_DIRECTORY.bits, size: 0 }), + (Err(e), _) => Err(e), } } @@ -661,13 +738,13 @@ pub fn metadata>(arch: &Archive, path: P) -> Result>(arch: &Archive, path: P) -> Result<(), i32> { +pub fn remove_dir>(arch: &Archive, path: P) -> IoResult<()> { unsafe { let path = to_utf16(path.as_ref()); let fs_path = fsMakePath(PathType::UTF16.into(), path.as_ptr() as _); let r = FSUSER_DeleteDirectory(arch.handle, fs_path); if r < 0 { - Err(r) + Err(IoError::new(IoErrorKind::Other, ::Error::from(r))) } else { Ok(()) } @@ -679,13 +756,13 @@ pub fn remove_dir>(arch: &Archive, path: P) -> Result<(), i32> { /// # Errors /// /// see `file::remove_file` and `fs::remove_dir` -pub fn remove_dir_all>(arch: &Archive, path: P) -> Result<(), i32> { +pub fn remove_dir_all>(arch: &Archive, path: P) -> IoResult<()> { unsafe { let path = to_utf16(path.as_ref()); let fs_path = fsMakePath(PathType::UTF16.into(), path.as_ptr() as _); let r = FSUSER_DeleteDirectoryRecursively(arch.handle, fs_path); if r < 0 { - Err(r) + Err(IoError::new(IoErrorKind::Other, ::Error::from(r))) } else { Ok(()) } @@ -703,7 +780,7 @@ pub fn remove_dir_all>(arch: &Archive, path: P) -> Result<(), i32 /// * The provided path doesn't exist. /// * The process lacks permissions to view the contents. /// * The path points at a non-directory file. -pub fn read_dir>(arch: &Archive, path: P) -> Result { +pub fn read_dir>(arch: &Archive, path: P) -> IoResult { unsafe { let mut handle = 0; let root = Arc::new(path.as_ref().to_path_buf()); @@ -711,7 +788,7 @@ pub fn read_dir>(arch: &Archive, path: P) -> Result let fs_path = fsMakePath(PathType::UTF16.into(), path.as_ptr() as _); let r = FSUSER_OpenDirectory(&mut handle, arch.handle, fs_path); if r < 0 { - Err(r) + Err(IoError::new(IoErrorKind::Other, ::Error::from(r))) } else { Ok(ReadDir { handle: Dir(handle), root: root, arch: arch}) } @@ -727,13 +804,13 @@ pub fn read_dir>(arch: &Archive, path: P) -> Result /// /// * path points to a directory. /// * The user lacks permissions to remove the file. -pub fn remove_file>(arch: &Archive, path: P) -> Result<(), i32> { +pub fn remove_file>(arch: &Archive, path: P) -> IoResult<()> { unsafe { let path = to_utf16(path.as_ref()); let fs_path = fsMakePath(PathType::UTF16.into(), path.as_ptr() as _); let r = FSUSER_DeleteFile(arch.handle, fs_path); if r < 0 { - Err(r) + Err(IoError::new(IoErrorKind::Other, ::Error::from(r))) } else { Ok(()) } @@ -750,7 +827,7 @@ pub fn remove_file>(arch: &Archive, path: P) -> Result<(), i32> { /// /// * from does not exist. /// * The user lacks permissions to view contents. -pub fn rename(arch: &Archive, from: P, to: Q) -> Result<(), i32> +pub fn rename(arch: &Archive, from: P, to: Q) -> IoResult<()> where P: AsRef, Q: AsRef { @@ -769,13 +846,13 @@ pub fn rename(arch: &Archive, from: P, to: Q) -> Result<(), i32> if r == 0 { return Ok(()) } - Err((r)) + Err(IoError::new(IoErrorKind::Other, ::Error::from(r))) } } // 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 @@ -787,8 +864,19 @@ fn truncate_utf16_at_nul<'a>(v: &'a [u16]) -> &'a [u16] { } } -// Adapted from sys/common/io.rs in libstd -unsafe fn read_to_end_uninitialized(f: &mut File, buf: &mut Vec) -> Result { +// Copied from sys/common/io.rs in libstd + +// 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. +unsafe fn read_to_end_uninitialized(r: &mut Read, buf: &mut Vec) -> IoResult { let start_len = buf.len(); buf.reserve(16); @@ -806,14 +894,56 @@ unsafe fn read_to_end_uninitialized(f: &mut File, buf: &mut Vec) -> Result { return Ok(buf.len() - start_len); } Ok(n) => { let len = buf.len() + n; buf.set_len(len); }, + Err(ref e) if e.kind() == IoErrorKind::Interrupted => { } Err(e) => { return Err(e); } } } } +impl Read for File { + fn read(&mut self, buf: &mut [u8]) -> IoResult { + self.read(buf) + } + + fn read_to_end(&mut self, buf: &mut Vec) -> IoResult { + self.read_to_end(buf) + } +} + +impl Write for File { + fn write(&mut self, buf: &[u8]) -> IoResult { + self.write(buf) + } + + fn flush(&mut self) -> IoResult<()> { + Ok(()) + } +} + +impl Seek for File { + fn seek(&mut self, pos: SeekFrom) -> IoResult { + match pos { + SeekFrom::Start(off) => { + self.offset = off; + }, + SeekFrom::End(off) => { + let mut temp = self.metadata()?.len() as i64; + temp += off; + self.offset = temp as u64; + }, + SeekFrom::Current(off) => { + let mut temp = self.offset as i64; + temp += off; + self.offset = temp as u64; + }, + } + Ok(self.offset) + } +} + impl Drop for Fs { fn drop(&mut self) { unsafe { @@ -874,7 +1004,7 @@ impl From for FS_ArchiveID { SdmcWriteOnly => ARCHIVE_SDMC_WRITE_ONLY, BossExtdata => ARCHIVE_BOSS_EXTDATA, CardSpiFS => ARCHIVE_CARD_SPIFS, - ExtDataAndBossExtdata => ARCHIVE_EXTDATA_AND_BOSS_EXTDATA, + ExtDataAndBossExtdata => ARCHIVE_EXTDATA_AND_BOSS_EXTDATA, SystemSaveData2 => ARCHIVE_SYSTEM_SAVEDATA2, NandRW => ARCHIVE_NAND_RW, NandRO => ARCHIVE_NAND_RO, diff --git a/src/services/gspgpu.rs b/ctru-rs/src/services/gspgpu.rs similarity index 98% rename from src/services/gspgpu.rs rename to ctru-rs/src/services/gspgpu.rs index efa153d..6bd972c 100644 --- a/src/services/gspgpu.rs +++ b/ctru-rs/src/services/gspgpu.rs @@ -1,6 +1,6 @@ use libctru::services::gspgpu; -use core::convert::From; +use std::convert::From; pub enum Event { Psc0, diff --git a/src/services/hid.rs b/ctru-rs/src/services/hid.rs similarity index 95% rename from src/services/hid.rs rename to ctru-rs/src/services/hid.rs index 1b90194..c703c21 100644 --- a/src/services/hid.rs +++ b/ctru-rs/src/services/hid.rs @@ -1,5 +1,5 @@ -use core::convert::Into; -use core::marker::PhantomData; +use std::convert::Into; +use std::marker::PhantomData; use libctru::services::hid; @@ -78,11 +78,11 @@ pub struct Hid { } impl Hid { - pub fn init() -> Result { + pub fn init() -> ::Result { unsafe { let r = hid::hidInit(); if r < 0 { - Err(r) + Err(::Error::from(r)) } else { Ok(Hid { pd: PhantomData }) } diff --git a/src/services/mod.rs b/ctru-rs/src/services/mod.rs similarity index 100% rename from src/services/mod.rs rename to ctru-rs/src/services/mod.rs diff --git a/src/srv.rs b/ctru-rs/src/srv.rs similarity index 75% rename from src/srv.rs rename to ctru-rs/src/srv.rs index 9c4388c..f0e7026 100644 --- a/src/srv.rs +++ b/ctru-rs/src/srv.rs @@ -1,17 +1,17 @@ use libctru::srv::*; -use core::marker::PhantomData; +use std::marker::PhantomData; pub struct Srv { pd: PhantomData, } impl Srv { - pub fn init() -> Result { + pub fn init() -> ::Result { unsafe { let r = srvInit(); if r < 0 { - Err(r) + Err(::Error::from(r)) } else { Ok(Srv { pd: PhantomData }) } diff --git a/ctru-sys/Cargo.toml b/ctru-sys/Cargo.toml index 578ee82..99e347b 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" } 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/gpu/gpu.rs b/ctru-sys/src/gpu/gpu.rs index 30e7a03..47ba027 100644 --- a/ctru-sys/src/gpu/gpu.rs +++ b/ctru-sys/src/gpu/gpu.rs @@ -1,26 +1,27 @@ /* automatically generated by rust-bindgen */ -#[inline] -pub fn GPUCMD_HEADER(incremental: u32, mask: u32, reg: u32) -> u32{ - (((incremental)<<31)|(((mask)&0xF)<<16)|((reg)&0x3FF)) +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] +extern "C" { + pub static mut gpuCmdBuf: *mut u32_; + pub static mut gpuCmdBufSize: u32_; + pub static mut gpuCmdBufOffset: u32_; } - extern "C" { - pub static mut gpuCmdBuf: *mut u32; - pub static mut gpuCmdBufSize: u32; - pub static mut gpuCmdBufOffset: u32; - - pub fn GPUCMD_SetBuffer(adr: *mut u32, size: u32, offset: u32); - pub fn GPUCMD_SetBufferOffset(offset: u32); - pub fn GPUCMD_GetBuffer(adr: *mut *mut u32, size: *mut u32, - offset: *mut u32); - pub fn GPUCMD_AddRawCommands(cmd: *mut u32, size: u32); + pub fn GPUCMD_SetBuffer(adr: *mut u32_, size: u32_, offset: u32_); + pub fn GPUCMD_SetBufferOffset(offset: u32_); + pub fn GPUCMD_GetBuffer(adr: *mut *mut u32_, size: *mut u32_, + offset: *mut u32_); + pub fn GPUCMD_AddRawCommands(cmd: *const u32_, size: u32_); pub fn GPUCMD_Run(); pub fn GPUCMD_FlushAndRun(); - pub fn GPUCMD_Add(header: u32, param: *mut u32, paramlength: u32); + pub fn GPUCMD_Add(header: u32_, param: *const u32_, paramlength: u32_); pub fn GPUCMD_Finalize(); - pub fn f32tof16(f: f32) -> u32; - pub fn f32tof20(f: f32) -> u32; - pub fn f32tof24(f: f32) -> u32; - pub fn f32tof31(f: f32) -> u32; + pub fn f32tof16(f: f32) -> u32_; + pub fn f32tof20(f: f32) -> u32_; + pub fn f32tof24(f: f32) -> u32_; + pub fn f32tof31(f: f32) -> u32_; } +use ::types::*; diff --git a/ctru-sys/src/gpu/gx.rs b/ctru-sys/src/gpu/gx.rs index 69eeddf..22b7949 100644 --- a/ctru-sys/src/gpu/gx.rs +++ b/ctru-sys/src/gpu/gx.rs @@ -1,94 +1,55 @@ -use ::Result; - -#[inline] -pub fn GX_BUFFER_DIM(w: u32, h: u32) { - (((h)<<16)|((w)&0xFFFF)); -} - -#[repr(C)] -pub enum GX_TRANSFER_FORMAT -{ - GX_TRANSFER_FMT_RGBA8 = 0, - GX_TRANSFER_FMT_RGB8 = 1, - GX_TRANSFER_FMT_RGB565 = 2, - GX_TRANSFER_FMT_RGB5A1 = 3, - GX_TRANSFER_FMT_RGBA4 = 4, -} - -#[repr(C)] -pub enum GX_TRANSFER_SCALE -{ - GX_TRANSFER_SCALE_NO = 0, - GX_TRANSFER_SCALE_X = 1, - GX_TRANSFER_SCALE_Y = 2, -} - -#[repr(C)] +/* 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 GX_TRANSFER_FORMAT { + GX_TRANSFER_FMT_RGBA8 = 0, + GX_TRANSFER_FMT_RGB8 = 1, + GX_TRANSFER_FMT_RGB565 = 2, + GX_TRANSFER_FMT_RGB5A1 = 3, + GX_TRANSFER_FMT_RGBA4 = 4, +} +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum GX_TRANSFER_SCALE { + GX_TRANSFER_SCALE_NO = 0, + GX_TRANSFER_SCALE_X = 1, + GX_TRANSFER_SCALE_XY = 2, +} +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] pub enum GX_FILL_CONTROL { - GX_FILL_TRIGGER = 0x001, - GX_FILL_FINISHED = 0x002, - GX_FILL_16BIT_DEPTH = 0x000, - GX_FILL_24BIT_DEPTH = 0x100, - GX_FILL_32BIT_DEPTH = 0x200, -} - -#[inline] -pub fn GX_TRANSFER_FLIP_VERT(x: i32) { - ((x)<<0); -} - -#[inline] -pub fn GX_TRANSFER_OUT_TILED(x: i32) { - ((x)<<1); -} - -#[inline] -pub fn GX_TRANSFER_RAW_COPY(x: i32) { - ((x)<<3); + GX_FILL_TRIGGER = 1, + GX_FILL_FINISHED = 2, + GX_FILL_16BIT_DEPTH = 0, + GX_FILL_24BIT_DEPTH = 256, + GX_FILL_32BIT_DEPTH = 512, } - -#[inline] -pub fn GX_TRANSFER_IN_FORMAT(x: i32) { - ((x)<<8); -} - -#[inline] -pub fn GX_TRANSFER_OUT_FORMAT(x: i32) { - ((x)<<12); -} - -#[inline] -pub fn GX_TRANSFER_SCALING(x: i32) { - ((x)<<24); -} - -#[inline] -pub fn GX_CMDLIST_BIT0() { - (1u32<<(0)); -} - -#[inline] -pub fn GX_CMNDLIST_FLUSH() { - (1u32<<(1)); +extern "C" { + pub static mut gxCmdBuf: *mut u32_; } - extern "C" { - pub static mut gxCmdBuf: *mut u32; - - pub fn GX_RequestDma(src: *mut u32, dst: *mut u32, length: u32) + pub fn GX_RequestDma(src: *mut u32_, dst: *mut u32_, length: u32_) -> Result; - pub fn GX_ProcessCommandList(buf0a: *mut u32, buf0s: u32, flags: u8) + pub fn GX_ProcessCommandList(buf0a: *mut u32_, buf0s: u32_, flags: u8_) -> Result; - pub fn GX_MemoryFill(buf0a: *mut u32, buf0v: u32, buf0e: *mut u32, - control0: u16, buf1a: *mut u32, buf1v: u32, - buf1e: *mut u32, control1: u16) -> Result; - pub fn GX_DisplayTransfer(inadr: *mut u32, indim: u32, - outadr: *mut u32, outdim: u32, flags: u32) + pub fn GX_MemoryFill(buf0a: *mut u32_, buf0v: u32_, buf0e: *mut u32_, + control0: u16_, buf1a: *mut u32_, buf1v: u32_, + buf1e: *mut u32_, control1: u16_) -> Result; + pub fn GX_DisplayTransfer(inadr: *mut u32_, indim: u32_, + outadr: *mut u32_, outdim: u32_, flags: u32_) -> Result; - pub fn GX_TextureCopy(inadr: *mut u32, indim: u32, outadr: *mut u32, - outdim: u32, size: u32, flags: u32) -> Result; - pub fn GX_FlushCacheRegions(buf0a: *mut u32, buf0s: u32, - buf1a: *mut u32, buf1s: u32, - buf2a: *mut u32, buf2s: u32) -> Result; + pub fn GX_TextureCopy(inadr: *mut u32_, indim: u32_, outadr: *mut u32_, + outdim: u32_, size: u32_, flags: u32_) -> Result; + pub fn GX_FlushCacheRegions(buf0a: *mut u32_, buf0s: u32_, + buf1a: *mut u32_, buf1s: u32_, + buf2a: *mut u32_, buf2s: u32_) -> Result; } - +use ::types::*; diff --git a/ctru-sys/src/gpu/shaderProgram.rs b/ctru-sys/src/gpu/shaderProgram.rs index f81f772..1c86711 100644 --- a/ctru-sys/src/gpu/shaderProgram.rs +++ b/ctru-sys/src/gpu/shaderProgram.rs @@ -1,89 +1,68 @@ -use ::Result; -use ::types::*; -use gpu::shbin::*; - +/* automatically generated by rust-bindgen */ +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] #[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed1 { - pub id: u32, - pub data: [u32; 3usize], -} -impl ::core::clone::Clone for Struct_Unnamed1 { - fn clone(&self) -> Self { *self } +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct float24Uniform_s { + pub id: u32_, + pub data: [u32_; 3usize], } -impl ::core::default::Default for Struct_Unnamed1 { +impl ::core::default::Default for float24Uniform_s { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } -pub type float24Uniform_s = Struct_Unnamed1; #[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed2 { +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct shaderInstance_s { pub dvle: *mut DVLE_s, - pub boolUniforms: u16, - pub boolUniformMask: u16, - pub intUniforms: [u32; 4usize], + pub boolUniforms: u16_, + pub boolUniformMask: u16_, + pub intUniforms: [u32_; 4usize], pub float24Uniforms: *mut float24Uniform_s, - pub intUniformMask: u8, - pub numFloat24Uniforms: u8, + pub intUniformMask: u8_, + pub numFloat24Uniforms: u8_, } -impl ::core::clone::Clone for Struct_Unnamed2 { - fn clone(&self) -> Self { *self } -} -impl ::core::default::Default for Struct_Unnamed2 { +impl ::core::default::Default for shaderInstance_s { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } -pub type shaderInstance_s = Struct_Unnamed2; #[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed3 { +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct shaderProgram_s { pub vertexShader: *mut shaderInstance_s, pub geometryShader: *mut shaderInstance_s, - pub geoShaderInputPermutation: [u32; 2usize], - pub geoShaderInputStride: u8, - pub geoShaderMode: u8, -} -impl ::core::clone::Clone for Struct_Unnamed3 { - fn clone(&self) -> Self { *self } + pub geoShaderInputPermutation: [u32_; 2usize], + pub geoShaderInputStride: u8_, } -impl ::core::default::Default for Struct_Unnamed3 { +impl ::core::default::Default for shaderProgram_s { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } -pub type shaderProgram_s = Struct_Unnamed3; -#[derive(Clone, Copy)] -#[repr(u32)] -pub enum Enum_Unnamed4 { - GSH_NORMAL = 0, - GSH_PARTICLE = 1, - GSH_SUBDIVISION_LOOP = 2, - GSH_SUBDIVISION_CATMULL_CLARK = 3, -} -pub type geoShaderMode = Enum_Unnamed4; extern "C" { pub fn shaderInstanceInit(si: *mut shaderInstance_s, dvle: *mut DVLE_s) -> Result; pub fn shaderInstanceFree(si: *mut shaderInstance_s) -> Result; - pub fn shaderInstanceSetBool(si: *mut shaderInstance_s, - id: i32, value: u8) - -> Result; - pub fn shaderInstanceGetBool(si: *mut shaderInstance_s, - id: i32, value: *mut u8) - -> Result; + pub fn shaderInstanceSetBool(si: *mut shaderInstance_s, id: ::libc::c_int, + value: u8) -> Result; + pub fn shaderInstanceGetBool(si: *mut shaderInstance_s, id: ::libc::c_int, + value: *mut u8) -> Result; pub fn shaderInstanceGetUniformLocation(si: *mut shaderInstance_s, - name: - *const u8) + name: *const ::libc::c_char) -> s8; pub fn shaderProgramInit(sp: *mut shaderProgram_s) -> Result; pub fn shaderProgramFree(sp: *mut shaderProgram_s) -> Result; pub fn shaderProgramSetVsh(sp: *mut shaderProgram_s, dvle: *mut DVLE_s) -> Result; pub fn shaderProgramSetGsh(sp: *mut shaderProgram_s, dvle: *mut DVLE_s, - stride: u8) -> Result; + stride: u8_) -> Result; pub fn shaderProgramSetGshInputPermutation(sp: *mut shaderProgram_s, - permutation: u64) -> Result; - pub fn shaderProgramSetGshMode(sp: *mut shaderProgram_s, - mode: geoShaderMode) -> Result; + permutation: u64_) -> Result; pub fn shaderProgramConfigure(sp: *mut shaderProgram_s, sendVshCode: u8, sendGshCode: u8) -> Result; pub fn shaderProgramUse(sp: *mut shaderProgram_s) -> Result; } +use ::types::*; +use super::shbin::*; diff --git a/ctru-sys/src/gpu/shbin.rs b/ctru-sys/src/gpu/shbin.rs index 1c5a453..67bf419 100644 --- a/ctru-sys/src/gpu/shbin.rs +++ b/ctru-sys/src/gpu/shbin.rs @@ -1,23 +1,25 @@ -use ::types::*; +/* automatically generated by rust-bindgen */ -#[derive(Clone, Copy)] +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] +#[derive(Copy, Clone)] #[repr(u32)] -pub enum Enum_Unnamed1 { - VERTEX_SHDR = 0, - GEOMETRY_SHDR = 1, -} -pub type DVLE_type = Enum_Unnamed1; -#[derive(Clone, Copy)] +#[derive(Debug)] +pub enum DVLE_type { VERTEX_SHDR = 0, GEOMETRY_SHDR = 1, } +#[derive(Copy, Clone)] #[repr(u32)] -pub enum Enum_Unnamed2 { +#[derive(Debug)] +pub enum DVLE_constantType { DVLE_CONST_BOOL = 0, DVLE_CONST_u8 = 1, DVLE_CONST_FLOAT24 = 2, } -pub type DVLE_constantType = Enum_Unnamed2; -#[derive(Clone, Copy)] +#[derive(Copy, Clone)] #[repr(u32)] -pub enum Enum_Unnamed3 { +#[derive(Debug)] +pub enum DVLE_outputAttribute_t { RESULT_POSITION = 0, RESULT_NORMALQUAT = 1, RESULT_COLOR = 2, @@ -26,111 +28,107 @@ pub enum Enum_Unnamed3 { RESULT_TEXCOORD1 = 5, RESULT_TEXCOORD2 = 6, RESULT_VIEW = 8, + RESULT_DUMMY = 9, } -pub type DVLE_outputAttribute_t = Enum_Unnamed3; -#[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed4 { - pub codeSize: u32, - pub codeData: *mut u32, - pub opdescSize: u32, - pub opcdescData: *mut u32, -} -impl ::core::clone::Clone for Struct_Unnamed4 { - fn clone(&self) -> Self { *self } +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum DVLE_geoShaderMode { + GSH_POINT = 0, + GSH_VARIABLE_PRIM = 1, + GSH_FIXED_PRIM = 2, } -impl ::core::default::Default for Struct_Unnamed4 { +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct DVLP_s { + pub codeSize: u32_, + pub codeData: *mut u32_, + pub opdescSize: u32_, + pub opcdescData: *mut u32_, +} +impl ::core::default::Default for DVLP_s { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } -pub type DVLP_s = Struct_Unnamed4; #[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed5 { - pub _type: u16, - pub id: u16, - pub data: [u32; 4usize], -} -impl ::core::clone::Clone for Struct_Unnamed5 { - fn clone(&self) -> Self { *self } -} -impl ::core::default::Default for Struct_Unnamed5 { +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct DVLE_constEntry_s { + pub type_: u16_, + pub id: u16_, + pub data: [u32_; 4usize], +} +impl ::core::default::Default for DVLE_constEntry_s { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } -pub type DVLE_constEntry_s = Struct_Unnamed5; #[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed6 { - pub _type: u16, - pub regID: u16, - pub mask: u8, - pub unk: [u8; 3usize], -} -impl ::core::clone::Clone for Struct_Unnamed6 { - fn clone(&self) -> Self { *self } -} -impl ::core::default::Default for Struct_Unnamed6 { +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct DVLE_outEntry_s { + pub type_: u16_, + pub regID: u16_, + pub mask: u8_, + pub unk: [u8_; 3usize], +} +impl ::core::default::Default for DVLE_outEntry_s { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } -pub type DVLE_outEntry_s = Struct_Unnamed6; #[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed7 { - pub symbolOffset: u32, - pub startReg: u16, - pub endReg: u16, -} -impl ::core::clone::Clone for Struct_Unnamed7 { - fn clone(&self) -> Self { *self } -} -impl ::core::default::Default for Struct_Unnamed7 { +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct DVLE_uniformEntry_s { + pub symbolOffset: u32_, + pub startReg: u16_, + pub endReg: u16_, +} +impl ::core::default::Default for DVLE_uniformEntry_s { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } -pub type DVLE_uniformEntry_s = Struct_Unnamed7; #[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed8 { - pub _type: DVLE_type, +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct DVLE_s { + pub type_: DVLE_type, + pub mergeOutmaps: u8, + pub gshMode: DVLE_geoShaderMode, + pub gshFixedVtxStart: u8_, + pub gshVariableVtxNum: u8_, + pub gshFixedVtxNum: u8_, pub dvlp: *mut DVLP_s, - pub mainOffset: u32, - pub endmainOffset: u32, - pub constTableSize: u32, + pub mainOffset: u32_, + pub endmainOffset: u32_, + pub constTableSize: u32_, pub constTableData: *mut DVLE_constEntry_s, - pub outTableSize: u32, + pub outTableSize: u32_, pub outTableData: *mut DVLE_outEntry_s, - pub uniformTableSize: u32, + pub uniformTableSize: u32_, pub uniformTableData: *mut DVLE_uniformEntry_s, - pub symbolTableData: *mut u8, - pub outmapMask: u8, - pub outmapData: [u32; 8usize], - pub outmapMode: u32, - pub outmapClock: u32, + pub symbolTableData: *mut ::libc::c_char, + pub outmapMask: u8_, + pub outmapData: [u32_; 8usize], + pub outmapMode: u32_, + pub outmapClock: u32_, } -impl ::core::clone::Clone for Struct_Unnamed8 { - fn clone(&self) -> Self { *self } -} -impl ::core::default::Default for Struct_Unnamed8 { +impl ::core::default::Default for DVLE_s { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } -pub type DVLE_s = Struct_Unnamed8; #[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed9 { - pub numDVLE: u32, +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct DVLB_s { + pub numDVLE: u32_, pub DVLP: DVLP_s, pub DVLE: *mut DVLE_s, } -impl ::core::clone::Clone for Struct_Unnamed9 { - fn clone(&self) -> Self { *self } -} -impl ::core::default::Default for Struct_Unnamed9 { +impl ::core::default::Default for DVLB_s { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } -pub type DVLB_s = Struct_Unnamed9; extern "C" { - pub fn DVLB_ParseFile(shbinData: *mut u32, shbinSize: u32) + pub fn DVLB_ParseFile(shbinData: *mut u32_, shbinSize: u32_) -> *mut DVLB_s; pub fn DVLB_Free(dvlb: *mut DVLB_s); pub fn DVLE_GetUniformRegister(dvle: *mut DVLE_s, - name: *const u8) -> s8; + name: *const ::libc::c_char) -> s8; pub fn DVLE_GenerateOutmap(dvle: *mut DVLE_s); } +use ::types::*; diff --git a/ctru-sys/src/lib.rs b/ctru-sys/src/lib.rs index b3cbfcb..5bbc54d 100644 --- a/ctru-sys/src/lib.rs +++ b/ctru-sys/src/lib.rs @@ -2,19 +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] -#![feature(question_mark)] #![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; @@ -26,8 +30,3 @@ pub mod types; pub use self::sys::*; pub use self::types::*; - -pub type Result = i32; -pub type Handle = u32; - -pub type ThreadFunc = Option ()>; 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 ce0df6c..c3dff74 100644 --- a/ctru-sys/src/os.rs +++ b/ctru-sys/src/os.rs @@ -1,54 +1,47 @@ -//TODO: Fix Bindgen's issues again. +/* automatically generated by rust-bindgen */ -use ::Result; -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/ac.rs b/ctru-sys/src/services/ac.rs index f23369f..926f453 100644 --- a/ctru-sys/src/services/ac.rs +++ b/ctru-sys/src/services/ac.rs @@ -1,8 +1,13 @@ -use ::Result; +/* automatically generated by rust-bindgen */ +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] extern "C" { pub fn acInit() -> Result; pub fn acExit(); pub fn acWaitInternetConnection() -> Result; - pub fn ACU_GetWifiStatus(out: *mut u32) -> Result; + pub fn ACU_GetWifiStatus(out: *mut u32_) -> Result; } +use ::types::*; diff --git a/ctru-sys/src/services/am.rs b/ctru-sys/src/services/am.rs index 971829e..9f7a445 100644 --- a/ctru-sys/src/services/am.rs +++ b/ctru-sys/src/services/am.rs @@ -1,49 +1,186 @@ -use ::{Handle, Result}; +/* automatically generated by rust-bindgen */ +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] #[repr(C)] -#[derive(Copy)] +#[derive(Copy, Clone)] +#[derive(Debug)] pub struct AM_TitleEntry { - pub titleID: u64, - pub size: u64, - pub version: u16, - pub unk: [u8; 6usize], + pub titleID: u64_, + pub size: u64_, + pub version: u16_, + pub unk: [u8_; 6usize], } - -impl ::core::clone::Clone for AM_TitleEntry { - fn clone(&self) -> Self { *self } -} - impl ::core::default::Default for AM_TitleEntry { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } - +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum Enum_Unnamed1 { + AM_STATUS_MASK_INSTALLING = 1, + AM_STATUS_MASK_AWAITING_FINALIZATION = 2, +} +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum AM_InstallStatus { + AM_STATUS_ABORTED = 2, + AM_STATUS_SAVED = 3, + AM_STATUS_INSTALL_IN_PROGRESS = 2050, + AM_STATUS_AWAITING_FINALIZATION = 2051, +} +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct AM_PendingTitleEntry { + pub titleId: u64_, + pub version: u16_, + pub status: u16_, + pub titleType: u32_, + pub unk: [u8_; 8usize], +} +impl ::core::default::Default for AM_PendingTitleEntry { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum Enum_Unnamed2 { + AM_DELETE_PENDING_NON_SYSTEM = 1, + AM_DELETE_PENDING_SYSTEM = 2, +} +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct AM_TWLPartitionInfo { + pub capacity: u64_, + pub freeSpace: u64_, + pub titlesCapacity: u64_, + pub titlesFreeSpace: u64_, +} +impl ::core::default::Default for AM_TWLPartitionInfo { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} extern "C" { pub fn amInit() -> Result; + pub fn amAppInit() -> Result; pub fn amExit(); pub fn amGetSessionHandle() -> *mut Handle; - pub fn AM_GetTitleCount(mediatype: u8, count: *mut u32) -> Result; - pub fn AM_GetTitleIdList(mediatype: u8, count: u32, titleIDs: *mut u64) + pub fn AM_GetTitleCount(mediatype: FS_MediaType, count: *mut u32_) + -> Result; + pub fn AM_GetTitleList(titlesRead: *mut u32_, mediatype: FS_MediaType, + titleCount: u32_, titleIds: *mut u64_) -> Result; + pub fn AM_GetTitleInfo(mediatype: FS_MediaType, titleCount: u32_, + titleIds: *mut u64_, titleInfo: *mut AM_TitleEntry) -> Result; - pub fn AM_GetDeviceId(deviceID: *mut u32) -> Result; - pub fn AM_ListTitles(mediatype: u8, titleCount: u32, - titleIdList: *mut u64, titleList: *mut AM_TitleEntry) + pub fn AM_GetTicketCount(count: *mut u32_) -> Result; + pub fn AM_GetTicketList(ticketsRead: *mut u32_, ticketCount: u32_, + skip: u32_, ticketIds: *mut u64_) -> Result; + pub fn AM_GetPendingTitleCount(count: *mut u32_, mediatype: FS_MediaType, + statusMask: u32_) -> Result; + pub fn AM_GetPendingTitleList(titlesRead: *mut u32_, titleCount: u32_, + mediatype: FS_MediaType, statusMask: u32_, + titleIds: *mut u64_) -> Result; + pub fn AM_GetPendingTitleInfo(titleCount: u32_, mediatype: FS_MediaType, + titleIds: *mut u64_, + titleInfo: *mut AM_PendingTitleEntry) -> Result; - pub fn AM_StartCiaInstall(mediatype: u8, ciaHandle: *mut Handle) + pub fn AM_GetDeviceId(deviceID: *mut u32_) -> Result; + pub fn AM_ExportTwlBackup(titleID: u64_, operation: u8_, + workbuf: *mut ::libc::c_void, + workbuf_size: u32_, + filepath: *const ::libc::c_char) -> Result; + pub fn AM_ImportTwlBackup(filehandle: Handle, operation: u8_, + buffer: *mut ::libc::c_void, size: u32_) + -> Result; + pub fn AM_ReadTwlBackupInfo(filehandle: Handle, + outinfo: *mut ::libc::c_void, + outinfo_size: u32_, + workbuf: *mut ::libc::c_void, + workbuf_size: u32_, + banner: *mut ::libc::c_void, + banner_size: u32_) -> Result; + pub fn AM_GetTWLPartitionInfo(info: *mut AM_TWLPartitionInfo) -> Result; + pub fn AM_StartCiaInstall(mediatype: FS_MediaType, ciaHandle: *mut Handle) -> Result; pub fn AM_StartDlpChildCiaInstall(ciaHandle: *mut Handle) -> Result; - pub fn AM_CancelCIAInstall(ciaHandle: *mut Handle) -> Result; - pub fn AM_FinishCiaInstall(mediatype: u8, ciaHandle: *mut Handle) + pub fn AM_CancelCIAInstall(ciaHandle: Handle) -> Result; + pub fn AM_FinishCiaInstall(ciaHandle: Handle) -> Result; + pub fn AM_DeleteTitle(mediatype: FS_MediaType, titleID: u64_) -> Result; + pub fn AM_DeleteAppTitle(mediatype: FS_MediaType, titleID: u64_) -> Result; - pub fn AM_DeleteTitle(mediatype: u8, titleID: u64) -> Result; - pub fn AM_DeleteAppTitle(mediatype: u8, titleID: u64) -> Result; - pub fn AM_InstallNativeFirm() -> Result; - pub fn AM_InstallFirm(titleID: u64) -> Result; - pub fn AM_GetTitleProductCode(mediatype: u8, titleID: u64, - productCode: *mut u8) + pub fn AM_DeleteTicket(ticketId: u64_) -> Result; + pub fn AM_DeletePendingTitle(mediatype: FS_MediaType, titleId: u64_) -> Result; - pub fn AM_GetCiaFileInfo(mediatype: u8, titleEntry: *mut AM_TitleEntry, + pub fn AM_DeletePendingTitles(mediatype: FS_MediaType, flags: u32_) + -> Result; + pub fn AM_DeleteAllPendingTitles(mediatype: FS_MediaType) -> Result; + pub fn AM_InstallNativeFirm() -> Result; + pub fn AM_InstallFirm(titleID: u64_) -> Result; + pub fn AM_GetTitleProductCode(mediatype: FS_MediaType, titleId: u64_, + productCode: *mut ::libc::c_char) -> Result; + pub fn AM_GetTitleExtDataId(extDataId: *mut u64_, mediatype: FS_MediaType, + titleId: u64_) -> Result; + pub fn AM_GetCiaFileInfo(mediatype: FS_MediaType, + titleEntry: *mut AM_TitleEntry, fileHandle: Handle) -> Result; + pub fn AM_GetCiaIcon(icon: *mut ::libc::c_void, fileHandle: Handle) + -> Result; + pub fn AM_GetCiaDependencies(dependencies: *mut u64_, fileHandle: Handle) + -> Result; + pub fn AM_GetCiaMetaOffset(metaOffset: *mut u64_, fileHandle: Handle) + -> Result; + pub fn AM_GetCiaCoreVersion(coreVersion: *mut u32_, fileHandle: Handle) + -> Result; + pub fn AM_GetCiaRequiredSpace(requiredSpace: *mut u64_, + mediaType: FS_MediaType, fileHandle: Handle) + -> Result; + pub fn AM_GetCiaMetaSection(meta: *mut ::libc::c_void, size: u32_, + fileHandle: Handle) -> Result; pub fn AM_InitializeExternalTitleDatabase(overwrite: u8) -> Result; pub fn AM_QueryAvailableExternalTitleDatabase(available: *mut u8) -> Result; + pub fn AM_InstallTicketBegin(ticketHandle: *mut Handle) -> Result; + pub fn AM_InstallTicketAbort(ticketHandle: Handle) -> Result; + pub fn AM_InstallTicketFinish(ticketHandle: Handle) -> Result; + pub fn AM_InstallTitleBegin(mediaType: FS_MediaType, titleId: u64_, + unk: u8) -> Result; + pub fn AM_InstallTitleStop() -> Result; + pub fn AM_InstallTitleResume(mediaType: FS_MediaType, titleId: u64_) + -> Result; + pub fn AM_InstallTitleAbort() -> Result; + pub fn AM_InstallTitleFinish() -> Result; + pub fn AM_CommitImportTitles(mediaType: FS_MediaType, titleCount: u32_, + temp: u8, titleIds: *mut u64_) -> Result; + pub fn AM_InstallTmdBegin(tmdHandle: *mut Handle) -> Result; + pub fn AM_InstallTmdAbort(tmdHandle: Handle) -> Result; + pub fn AM_InstallTmdFinish(tmdHandle: Handle, unk: u8) -> Result; + pub fn AM_CreateImportContentContexts(contentCount: u32_, + contentIndices: *mut u16_) + -> Result; + pub fn AM_InstallContentBegin(contentHandle: *mut Handle, index: u16_) + -> Result; + pub fn AM_InstallContentStop(contentHandle: Handle) -> Result; + pub fn AM_InstallContentResume(contentHandle: *mut Handle, + resumeOffset: *mut u64_, index: u16_) + -> Result; + pub fn AM_InstallContentCancel(contentHandle: Handle) -> Result; + pub fn AM_InstallContentFinish(contentHandle: Handle) -> Result; + pub fn AM_ImportCertificates(cert1Size: u32_, cert1: *mut ::libc::c_void, + cert2Size: u32_, cert2: *mut ::libc::c_void, + cert3Size: u32_, cert3: *mut ::libc::c_void, + cert4Size: u32_, cert4: *mut ::libc::c_void) + -> Result; + pub fn AM_ImportCertificate(certSize: u32_, cert: *mut ::libc::c_void) + -> Result; + pub fn AM_CommitImportTitlesAndUpdateFirmwareAuto(mediaType: FS_MediaType, + titleCount: u32_, + temp: u8, + titleIds: *mut u64_) + -> Result; } +use ::types::*; +use super::fs::FS_MediaType; diff --git a/ctru-sys/src/services/ampxi.rs b/ctru-sys/src/services/ampxi.rs new file mode 100644 index 0000000..4dc27d4 --- /dev/null +++ b/ctru-sys/src/services/ampxi.rs @@ -0,0 +1,18 @@ +/* automatically generated by rust-bindgen */ + +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] +extern "C" { + pub fn ampxiInit(servhandle: Handle) -> Result; + pub fn ampxiExit(); + pub fn AMPXI_WriteTWLSavedata(titleid: u64_, buffer: *mut u8_, size: u32_, + image_filepos: u32_, section_type: u8_, + operation: u8_) -> Result; + pub fn AMPXI_InstallTitlesFinish(mediaType: FS_MediaType, db: u8_, + titlecount: u32_, tidlist: *mut u64_) + -> Result; +} +use ::types::*; +use super::fs::FS_MediaType; diff --git a/ctru-sys/src/services/apt.rs b/ctru-sys/src/services/apt.rs index 8c32e91..d713102 100644 --- a/ctru-sys/src/services/apt.rs +++ b/ctru-sys/src/services/apt.rs @@ -1,61 +1,121 @@ -use ::{Result, Handle}; -use ::libc::c_void; +/* automatically generated by rust-bindgen */ -#[repr(C)] -#[derive(Clone, Copy)] +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] pub enum NS_APPID { - APPID_HOMEMENU = 0x101, // Home Menu - APPID_CAMERA = 0x110, // Camera applet - APPID_FRIENDS_LIST = 0x112, // Friends List applet - APPID_GAME_NOTES = 0x113, // Game Notes applet - APPID_WEB = 0x114, // Internet Browser - APPID_INSTRUCTION_MANUAL = 0x115, // Instruction Manual applet - APPID_NOTIFICATIONS = 0x116, // Notifications applet - APPID_MIIVERSE = 0x117, // Miiverse applet - APPID_MIIVERSE_POSTING = 0x118, - APPID_AMIIBO_SETTINGS = 0x119, - APPID_APPLICATION = 0x300, // Application - APPID_ESHOP = 0x301, - APPID_SOFTWARE_KEYBOARD = 0x401, // Software Keyboard - APPID_APPLETED = 0x402, // appletEd - APPID_PNOTE_AP = 0x404, // PNOTE_AP - APPID_SNOTE_AP = 0x405, // SNOTE_AP - APPID_ERROR = 0x406, // error - APPID_MINT = 0x407, // mint - APPID_EXTRAPAD = 0x408, // extrapad - APPID_MEMOLIB = 0x409, // memolib + APPID_NONE = 0, + APPID_HOMEMENU = 257, + APPID_CAMERA = 272, + APPID_FRIENDS_LIST = 274, + APPID_GAME_NOTES = 275, + APPID_WEB = 276, + APPID_INSTRUCTION_MANUAL = 277, + APPID_NOTIFICATIONS = 278, + APPID_MIIVERSE = 279, + APPID_MIIVERSE_POSTING = 280, + APPID_AMIIBO_SETTINGS = 281, + APPID_APPLICATION = 768, + APPID_ESHOP = 769, + APPID_SOFTWARE_KEYBOARD = 1025, + APPID_APPLETED = 1026, + APPID_PNOTE_AP = 1028, + APPID_SNOTE_AP = 1029, + APPID_ERROR = 1030, + APPID_MINT = 1031, + APPID_EXTRAPAD = 1032, + APPID_MEMOLIB = 1033, } - -#[repr(C)] -#[derive(Clone, Copy)] -pub enum APT_AppStatus { - APP_NOTINITIALIZED = 0, - APP_RUNNING = 1, - APP_SUSPENDED = 2, - APP_EXITING = 3, - APP_SUSPENDING = 4, - APP_SLEEPMODE = 5, - APP_PREPARE_SLEEPMODE = 6, - APP_APPLETSTARTED = 7, - APP_APPLETCLOSED = 8, +#[derive(Copy, Clone)] +#[repr(i32)] +#[derive(Debug)] +pub enum APT_AppletPos { + APTPOS_NONE = -1, + APTPOS_APP = 0, + APTPOS_APPLIB = 1, + APTPOS_SYS = 2, + APTPOS_SYSLIB = 3, + APTPOS_RESIDENT = 4, } - -#[repr(C)] -#[derive(Clone, Copy)] +pub type APT_AppletAttr = u8_; +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum APT_QueryReply { + APTREPLY_REJECT = 0, + APTREPLY_ACCEPT = 1, + APTREPLY_LATER = 2, +} +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] pub enum APT_Signal { + APTSIGNAL_NONE = 0, APTSIGNAL_HOMEBUTTON = 1, - APTSIGNAL_PREPARESLEEP = 3, - APTSIGNAL_ENTERSLEEP = 5, - APTSIGNAL_WAKEUP = 6, - APTSIGNAL_ENABLE = 7, + APTSIGNAL_HOMEBUTTON2 = 2, + APTSIGNAL_SLEEP_QUERY = 3, + APTSIGNAL_SLEEP_CANCEL = 4, + APTSIGNAL_SLEEP_ENTER = 5, + APTSIGNAL_SLEEP_WAKEUP = 6, + APTSIGNAL_SHUTDOWN = 7, APTSIGNAL_POWERBUTTON = 8, - APTSIGNAL_UTILITY = 9, - APTSIGNAL_SLEEPSYSTEM = 10, - APTSIGNAL_ERROR = 11, + APTSIGNAL_POWERBUTTON2 = 9, + APTSIGNAL_TRY_SLEEP = 10, + APTSIGNAL_ORDERTOCLOSE = 11, +} +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum APT_Command { + APTCMD_NONE = 0, + APTCMD_WAKEUP = 1, + APTCMD_REQUEST = 2, + APTCMD_RESPONSE = 3, + APTCMD_EXIT = 4, + APTCMD_MESSAGE = 5, + APTCMD_HOMEBUTTON_ONCE = 6, + APTCMD_HOMEBUTTON_TWICE = 7, + APTCMD_DSP_SLEEP = 8, + APTCMD_DSP_WAKEUP = 9, + APTCMD_WAKEUP_EXIT = 10, + APTCMD_WAKEUP_PAUSE = 11, + APTCMD_WAKEUP_CANCEL = 12, + APTCMD_WAKEUP_CANCELALL = 13, + APTCMD_WAKEUP_POWERBUTTON = 14, + APTCMD_WAKEUP_JUMPTOHOME = 15, + APTCMD_SYSAPPLET_REQUEST = 16, + APTCMD_WAKEUP_LAUNCHAPP = 17, } - #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct aptCaptureBufInfo { + pub size: u32_, + pub is3D: u32_, + pub top: Struct_Unnamed1, + pub bottom: Struct_Unnamed1, +} +impl ::core::default::Default for aptCaptureBufInfo { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct Struct_Unnamed1 { + pub leftOffset: u32_, + pub rightOffset: u32_, + pub format: u32_, +} +impl ::core::default::Default for Struct_Unnamed1 { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] pub enum APT_HookType { APTHOOK_ONSUSPEND = 0, APTHOOK_ONRESTORE = 1, @@ -64,106 +124,118 @@ pub enum APT_HookType { APTHOOK_ONEXIT = 4, APTHOOK_COUNT = 5, } - -pub type aptHookFn = Option; - +pub type aptHookFn = + ::core::option::Option; #[repr(C)] -#[derive(Copy)] -pub struct aptHookCookie { - pub next: *mut aptHookCookie, +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct tag_aptHookCookie { + pub next: *mut tag_aptHookCookie, pub callback: aptHookFn, - pub param: *mut c_void, -} -impl ::core::clone::Clone for aptHookCookie { - fn clone(&self) -> Self { *self } + pub param: *mut ::libc::c_void, } -impl ::core::default::Default for aptHookCookie { +impl ::core::default::Default for tag_aptHookCookie { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } - -extern "C" { - pub static mut aptEvents: [Handle; 3usize]; -} +pub type aptHookCookie = tag_aptHookCookie; +pub type aptMessageCb = + ::core::option::Option; extern "C" { pub fn aptInit() -> Result; pub fn aptExit(); - pub fn aptOpenSession(); - pub fn aptCloseSession(); - pub fn aptSetStatus(status: APT_AppStatus); - pub fn aptGetStatus() -> APT_AppStatus; - pub fn aptGetStatusPower() -> u32; - pub fn aptSetStatusPower(status: u32); - pub fn aptReturnToMenu(); - pub fn aptWaitStatusEvent(); - pub fn aptSignalReadyForSleep(); - pub fn aptGetMenuAppID() -> NS_APPID; + pub fn aptSendCommand(aptcmdbuf: *mut u32_) -> Result; + pub fn aptIsSleepAllowed() -> u8; + pub fn aptSetSleepAllowed(allowed: u8); pub fn aptMainLoop() -> u8; pub fn aptHook(cookie: *mut aptHookCookie, callback: aptHookFn, - param: *mut c_void); + param: *mut ::libc::c_void); pub fn aptUnhook(cookie: *mut aptHookCookie); - pub fn APT_GetLockHandle(flags: u16, lockHandle: *mut Handle) -> Result; - pub fn APT_Initialize(appId: NS_APPID, eventHandle1: *mut Handle, - eventHandle2: *mut Handle) -> Result; + pub fn aptSetMessageCallback(callback: aptMessageCb, + user: *mut ::libc::c_void); + pub fn aptLaunchLibraryApplet(appId: NS_APPID, buf: *mut ::libc::c_void, + 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) + -> Result; pub fn APT_Finalize(appId: NS_APPID) -> Result; pub fn APT_HardwareResetAsync() -> Result; - pub fn APT_Enable(a: u32) -> Result; - pub fn APT_GetAppletManInfo(inval: u8, outval8: *mut u8, - outval32: *mut u32, + pub fn APT_Enable(attr: APT_AppletAttr) -> Result; + pub fn APT_GetAppletManInfo(inpos: APT_AppletPos, + outpos: *mut APT_AppletPos, + req_appid: *mut NS_APPID, menu_appid: *mut NS_APPID, active_appid: *mut NS_APPID) -> Result; - pub fn APT_GetAppletInfo(appID: NS_APPID, pProgramID: *mut u64, - pMediaType: *mut u8, pRegistered: *mut u8, - pLoadState: *mut u8, pAttributes: *mut u32) - -> Result; - pub fn APT_GetAppletProgramInfo(id: u32, flags: u32, - titleversion: *mut u16) -> Result; - pub fn APT_GetProgramID(pProgramID: *mut u64) -> Result; + pub fn APT_GetAppletInfo(appID: NS_APPID, pProgramID: *mut u64_, + pMediaType: *mut u8_, pRegistered: *mut u8, + pLoadState: *mut u8, + pAttributes: *mut APT_AppletAttr) -> Result; + pub fn APT_GetAppletProgramInfo(id: u32_, flags: u32_, + titleversion: *mut u16_) -> Result; + pub fn APT_GetProgramID(pProgramID: *mut u64_) -> Result; pub fn APT_PrepareToJumpToHomeMenu() -> Result; - pub fn APT_JumpToHomeMenu(param: *const u8, paramSize: usize, + pub fn APT_JumpToHomeMenu(param: *const ::libc::c_void, paramSize: ::libc::size_t, handle: Handle) -> Result; - pub fn APT_PrepareToJumpToApplication(a: u32) -> Result; - pub fn APT_JumpToApplication(param: *const u8, paramSize: usize, - handle: Handle) -> Result; + pub fn APT_PrepareToJumpToApplication(exiting: u8) -> Result; + pub fn APT_JumpToApplication(param: *const ::libc::c_void, + 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) + pub fn APT_InquireNotification(appID: u32_, signalType: *mut APT_Signal) -> Result; pub fn APT_NotifyToWait(appID: NS_APPID) -> Result; - pub fn APT_AppletUtility(out: *mut u32, a: u32, size1: u32, - buf1: *mut u8, size2: u32, buf2: *mut u8) + pub fn APT_AppletUtility(id: ::libc::c_int, out: *mut ::libc::c_void, + 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: ::libc::size_t, sender: *mut NS_APPID, + command: *mut APT_Command, + actualSize: *mut ::libc::size_t, + parameter: *mut Handle) -> Result; + pub fn APT_ReceiveParameter(appID: NS_APPID, buffer: *mut ::libc::c_void, + bufferSize: ::libc::size_t, sender: *mut NS_APPID, + command: *mut APT_Command, + actualSize: *mut ::libc::size_t, + parameter: *mut Handle) -> Result; + pub fn APT_SendParameter(source: NS_APPID, dest: NS_APPID, + command: APT_Command, + buffer: *const ::libc::c_void, bufferSize: u32_, + parameter: Handle) -> Result; + pub fn APT_CancelParameter(source: NS_APPID, dest: NS_APPID, + success: *mut u8) -> Result; + pub fn APT_SendCaptureBufferInfo(captureBuf: *const aptCaptureBufInfo) -> Result; - pub fn APT_GlanceParameter(appID: NS_APPID, bufferSize: u32, - buffer: *mut u32, actualSize: *mut u32, - signalType: *mut u8) -> Result; - pub fn APT_ReceiveParameter(appID: NS_APPID, bufferSize: u32, - buffer: *mut u32, actualSize: *mut u32, - signalType: *mut u8) -> Result; - pub fn APT_SendParameter(src_appID: NS_APPID, dst_appID: NS_APPID, - bufferSize: u32, buffer: *mut u32, - paramhandle: Handle, signalType: u8) -> Result; - pub fn APT_SendCaptureBufferInfo(bufferSize: u32, buffer: *mut u32) + pub fn APT_ReplySleepQuery(appID: NS_APPID, reply: APT_QueryReply) -> Result; - pub fn APT_ReplySleepQuery(appID: NS_APPID, a: u32) -> Result; pub fn APT_ReplySleepNotificationComplete(appID: NS_APPID) -> Result; - pub fn APT_PrepareToCloseApplication(a: u8) -> Result; - pub fn APT_CloseApplication(param: *const u8, paramSize: usize, - handle: Handle) -> Result; - pub fn APT_SetAppCpuTimeLimit(percent: u32) -> Result; - pub fn APT_GetAppCpuTimeLimit(percent: *mut u32) -> Result; - pub fn APT_CheckNew3DS_Application(out: *mut u8) -> Result; - pub fn APT_CheckNew3DS_System(out: *mut u8) -> Result; + pub fn APT_PrepareToCloseApplication(cancelPreload: u8) -> Result; + pub fn APT_CloseApplication(param: *const ::libc::c_void, + 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_PrepareToDoAppJump(flags: u8, programID: u64, mediatype: u8) - -> Result; - pub fn APT_DoAppJump(NSbuf0Size: u32, NSbuf1Size: u32, - NSbuf0Ptr: *mut u8, NSbuf1Ptr: *mut u8) -> Result; + pub fn APT_PrepareToDoApplicationJump(flags: u8_, programID: u64_, + mediatype: u8_) -> Result; + pub fn APT_DoApplicationJump(param: *const ::libc::c_void, + 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, inhandle: Handle, - parambuf: *mut u32, parambufsize: u32) - -> Result; - pub fn APT_LaunchLibraryApplet(appID: NS_APPID, inhandle: Handle, - parambuf: *mut u32, parambufsize: u32) + pub fn APT_StartLibraryApplet(appID: NS_APPID, + param: *const ::libc::c_void, + paramSize: ::libc::size_t, handle: Handle) -> Result; pub fn APT_PrepareToStartSystemApplet(appID: NS_APPID) -> Result; - pub fn APT_StartSystemApplet(appID: NS_APPID, bufSize: u32, - applHandle: Handle, buf: *mut u8) -> Result; + pub fn APT_StartSystemApplet(appID: NS_APPID, + param: *const ::libc::c_void, + paramSize: ::libc::size_t, handle: Handle) -> Result; + pub fn APT_GetSharedFont(fontHandle: *mut Handle, mapAddr: *mut u32_) + -> Result; } +use ::types::*; diff --git a/ctru-sys/src/services/cam.rs b/ctru-sys/src/services/cam.rs index 811956b..872fb39 100644 --- a/ctru-sys/src/services/cam.rs +++ b/ctru-sys/src/services/cam.rs @@ -1,20 +1,21 @@ -// TODO: Determine if anonymous enums are properly represented (they probably aren't) +/* automatically generated by rust-bindgen */ -use ::{Handle, Result}; -use libc::c_void; -use ::types::*; - -#[derive(Clone, Copy)] -#[repr(C)] +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] pub enum Enum_Unnamed1 { PORT_NONE = 0, PORT_CAM1 = 1, PORT_CAM2 = 2, PORT_BOTH = 3, } - -#[derive(Clone, Copy)] -#[repr(C)] +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] pub enum Enum_Unnamed2 { SELECT_NONE = 0, SELECT_OUT1 = 1, @@ -25,30 +26,29 @@ pub enum Enum_Unnamed2 { SELECT_IN1_OUT2 = 6, SELECT_ALL = 7, } -#[derive(Clone, Copy)] -#[repr(C)] -pub enum Enum_Unnamed3 { +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum CAMU_Context { CONTEXT_NONE = 0, CONTEXT_A = 1, CONTEXT_B = 2, CONTEXT_BOTH = 3, } - -pub type CAMU_Context = Enum_Unnamed3; -#[derive(Clone, Copy)] -#[repr(C)] -pub enum Enum_Unnamed4 { +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum CAMU_Flip { FLIP_NONE = 0, FLIP_HORIZONTAL = 1, FLIP_VERTICAL = 2, FLIP_REVERSE = 3, } -pub type CAMU_Flip = Enum_Unnamed4; - -pub const SIZE_CTR_BOTTOM_LCD: Enum_Unnamed5 = Enum_Unnamed5::SIZE_QVGA; -#[derive(Clone, Copy)] -#[repr(C)] -pub enum Enum_Unnamed5 { +pub const SIZE_CTR_BOTTOM_LCD: CAMU_Size = CAMU_Size::SIZE_QVGA; +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum CAMU_Size { SIZE_VGA = 0, SIZE_QVGA = 1, SIZE_QQVGA = 2, @@ -58,10 +58,9 @@ pub enum Enum_Unnamed5 { SIZE_DS_LCDx4 = 6, SIZE_CTR_TOP_LCD = 7, } -pub type CAMU_Size = Enum_Unnamed5; - -#[derive(Clone, Copy)] -#[repr(C)] +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] pub enum CAMU_FrameRate { FRAME_RATE_15 = 0, FRAME_RATE_15_TO_5 = 1, @@ -77,24 +76,24 @@ pub enum CAMU_FrameRate { FRAME_RATE_20_TO_10 = 11, FRAME_RATE_30_TO_10 = 12, } - -pub const WHITE_BALANCE_NORMAL: Enum_Unnamed7 = - Enum_Unnamed7::WHITE_BALANCE_AUTO; -pub const WHITE_BALANCE_TUNGSTEN: Enum_Unnamed7 = - Enum_Unnamed7::WHITE_BALANCE_3200K; -pub const WHITE_BALANCE_WHITE_FLUORESCENT_LIGHT: Enum_Unnamed7 = - Enum_Unnamed7::WHITE_BALANCE_4150K; -pub const WHITE_BALANCE_DAYLIGHT: Enum_Unnamed7 = - Enum_Unnamed7::WHITE_BALANCE_5200K; -pub const WHITE_BALANCE_CLOUDY: Enum_Unnamed7 = - Enum_Unnamed7::WHITE_BALANCE_6000K; -pub const WHITE_BALANCE_HORIZON: Enum_Unnamed7 = - Enum_Unnamed7::WHITE_BALANCE_6000K; -pub const WHITE_BALANCE_SHADE: Enum_Unnamed7 = - Enum_Unnamed7::WHITE_BALANCE_7000K; -#[derive(Clone, Copy)] -#[repr(C)] -pub enum Enum_Unnamed7 { +pub const WHITE_BALANCE_NORMAL: CAMU_WhiteBalance = + CAMU_WhiteBalance::WHITE_BALANCE_AUTO; +pub const WHITE_BALANCE_TUNGSTEN: CAMU_WhiteBalance = + CAMU_WhiteBalance::WHITE_BALANCE_3200K; +pub const WHITE_BALANCE_WHITE_FLUORESCENT_LIGHT: CAMU_WhiteBalance = + CAMU_WhiteBalance::WHITE_BALANCE_4150K; +pub const WHITE_BALANCE_DAYLIGHT: CAMU_WhiteBalance = + CAMU_WhiteBalance::WHITE_BALANCE_5200K; +pub const WHITE_BALANCE_CLOUDY: CAMU_WhiteBalance = + CAMU_WhiteBalance::WHITE_BALANCE_6000K; +pub const WHITE_BALANCE_HORIZON: CAMU_WhiteBalance = + CAMU_WhiteBalance::WHITE_BALANCE_6000K; +pub const WHITE_BALANCE_SHADE: CAMU_WhiteBalance = + CAMU_WhiteBalance::WHITE_BALANCE_7000K; +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum CAMU_WhiteBalance { WHITE_BALANCE_AUTO = 0, WHITE_BALANCE_3200K = 1, WHITE_BALANCE_4150K = 2, @@ -102,20 +101,20 @@ pub enum Enum_Unnamed7 { WHITE_BALANCE_6000K = 4, WHITE_BALANCE_7000K = 5, } -pub type CAMU_WhiteBalance = Enum_Unnamed7; -#[derive(Clone, Copy)] -#[repr(C)] -pub enum Enum_Unnamed8 { +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum CAMU_PhotoMode { PHOTO_MODE_NORMAL = 0, PHOTO_MODE_PORTRAIT = 1, PHOTO_MODE_LANDSCAPE = 2, PHOTO_MODE_NIGHTVIEW = 3, PHOTO_MODE_LETTER = 4, } -pub type CAMU_PhotoMode = Enum_Unnamed8; -#[derive(Clone, Copy)] -#[repr(C)] -pub enum Enum_Unnamed9 { +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum CAMU_Effect { EFFECT_NONE = 0, EFFECT_MONO = 1, EFFECT_SEPIA = 2, @@ -123,14 +122,13 @@ pub enum Enum_Unnamed9 { EFFECT_NEGAFILM = 4, EFFECT_SEPIA01 = 5, } -pub type CAMU_Effect = Enum_Unnamed9; -pub const CONTRAST_LOW: Enum_Unnamed10 = Enum_Unnamed10::CONTRAST_PATTERN_05; -pub const CONTRAST_NORMAL: Enum_Unnamed10 = - Enum_Unnamed10::CONTRAST_PATTERN_06; -pub const CONTRAST_HIGH: Enum_Unnamed10 = Enum_Unnamed10::CONTRAST_PATTERN_07; -#[derive(Clone, Copy)] -#[repr(C)] -pub enum Enum_Unnamed10 { +pub const CONTRAST_LOW: CAMU_Contrast = CAMU_Contrast::CONTRAST_PATTERN_05; +pub const CONTRAST_NORMAL: CAMU_Contrast = CAMU_Contrast::CONTRAST_PATTERN_06; +pub const CONTRAST_HIGH: CAMU_Contrast = CAMU_Contrast::CONTRAST_PATTERN_07; +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum CAMU_Contrast { CONTRAST_PATTERN_01 = 0, CONTRAST_PATTERN_02 = 1, CONTRAST_PATTERN_03 = 2, @@ -143,60 +141,57 @@ pub enum Enum_Unnamed10 { CONTRAST_PATTERN_10 = 9, CONTRAST_PATTERN_11 = 10, } -pub type CAMU_Contrast = Enum_Unnamed10; -pub const LENS_CORRECTION_DARK: Enum_Unnamed11 = - Enum_Unnamed11::LENS_CORRECTION_OFF; -pub const LENS_CORRECTION_NORMAL: Enum_Unnamed11 = - Enum_Unnamed11::LENS_CORRECTION_ON_70; -pub const LENS_CORRECTION_BRIGHT: Enum_Unnamed11 = - Enum_Unnamed11::LENS_CORRECTION_ON_90; -#[derive(Clone, Copy)] -#[repr(C)] -pub enum Enum_Unnamed11 { +pub const LENS_CORRECTION_DARK: CAMU_LensCorrection = + CAMU_LensCorrection::LENS_CORRECTION_OFF; +pub const LENS_CORRECTION_NORMAL: CAMU_LensCorrection = + CAMU_LensCorrection::LENS_CORRECTION_ON_70; +pub const LENS_CORRECTION_BRIGHT: CAMU_LensCorrection = + CAMU_LensCorrection::LENS_CORRECTION_ON_90; +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum CAMU_LensCorrection { LENS_CORRECTION_OFF = 0, LENS_CORRECTION_ON_70 = 1, LENS_CORRECTION_ON_90 = 2, } -pub type CAMU_LensCorrection = Enum_Unnamed11; -#[derive(Clone, Copy)] -#[repr(C)] -pub enum Enum_Unnamed12 { OUTPUT_YUV_422 = 0, OUTPUT_RGB_565 = 1, } -pub type CAMU_OutputFormat = Enum_Unnamed12; -#[derive(Clone, Copy)] -#[repr(C)] -pub enum Enum_Unnamed13 { +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum CAMU_OutputFormat { OUTPUT_YUV_422 = 0, OUTPUT_RGB_565 = 1, } +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum CAMU_ShutterSoundType { SHUTTER_SOUND_TYPE_NORMAL = 0, SHUTTER_SOUND_TYPE_MOVIE = 1, SHUTTER_SOUND_TYPE_MOVIE_END = 2, } -pub type CAMU_ShutterSoundType = Enum_Unnamed13; #[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed14 { +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct CAMU_ImageQualityCalibrationData { pub aeBaseTarget: s16, pub kRL: s16, pub kGL: s16, pub kBL: s16, pub ccmPosition: s16, - pub awbCcmL9Right: u16, - pub awbCcmL9Left: u16, - pub awbCcmL10Right: u16, - pub awbCcmL10Left: u16, - pub awbX0Right: u16, - pub awbX0Left: u16, -} -impl ::core::clone::Clone for Struct_Unnamed14 { - fn clone(&self) -> Self { *self } + pub awbCcmL9Right: u16_, + pub awbCcmL9Left: u16_, + pub awbCcmL10Right: u16_, + pub awbCcmL10Left: u16_, + pub awbX0Right: u16_, + pub awbX0Left: u16_, } -impl ::core::default::Default for Struct_Unnamed14 { +impl ::core::default::Default for CAMU_ImageQualityCalibrationData { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } -pub type CAMU_ImageQualityCalibrationData = Struct_Unnamed14; #[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed15 { - pub isValidRotationXY: u8, - pub padding: [u8; 3usize], +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct CAMU_StereoCameraCalibrationData { + pub isValidRotationXY: u8_, + pub padding: [u8_; 3usize], pub scale: f32, pub rotationZ: f32, pub translationX: f32, @@ -209,30 +204,27 @@ pub struct Struct_Unnamed15 { pub distanceCameras: f32, pub imageWidth: s16, pub imageHeight: s16, - pub reserved: [u8; 16usize], + pub reserved: [u8_; 16usize], } -impl ::core::clone::Clone for Struct_Unnamed15 { - fn clone(&self) -> Self { *self } -} -impl ::core::default::Default for Struct_Unnamed15 { +impl ::core::default::Default for CAMU_StereoCameraCalibrationData { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } -pub type CAMU_StereoCameraCalibrationData = Struct_Unnamed15; #[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed16 { - pub camera: u8, +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct CAMU_PackageParameterCameraSelect { + pub camera: u8_, pub exposure: s8, - pub whiteBalance: u8, + pub whiteBalance: u8_, pub sharpness: s8, - pub autoExposureOn: u8, - pub autoWhiteBalanceOn: u8, - pub frameRate: u8, - pub photoMode: u8, - pub contrast: u8, - pub lensCorrection: u8, - pub noiseFilterOn: u8, - pub padding: u8, + pub autoExposureOn: u8_, + pub autoWhiteBalanceOn: u8_, + pub frameRate: u8_, + pub photoMode: u8_, + pub contrast: u8_, + pub lensCorrection: u8_, + pub noiseFilterOn: u8_, + pub padding: u8_, pub autoExposureWindowX: s16, pub autoExposureWindowY: s16, pub autoExposureWindowWidth: s16, @@ -242,36 +234,30 @@ pub struct Struct_Unnamed16 { pub autoWhiteBalanceWindowWidth: s16, pub autoWhiteBalanceWindowHeight: s16, } -impl ::core::clone::Clone for Struct_Unnamed16 { - fn clone(&self) -> Self { *self } -} -impl ::core::default::Default for Struct_Unnamed16 { +impl ::core::default::Default for CAMU_PackageParameterCameraSelect { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } -pub type CAMU_PackageParameterCameraSelect = Struct_Unnamed16; #[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed17 { - pub camera: u8, - pub context: u8, - pub flip: u8, - pub effect: u8, - pub size: u8, +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct CAMU_PackageParameterContext { + pub camera: u8_, + pub context: u8_, + pub flip: u8_, + pub effect: u8_, + pub size: u8_, } -impl ::core::clone::Clone for Struct_Unnamed17 { - fn clone(&self) -> Self { *self } -} -impl ::core::default::Default for Struct_Unnamed17 { +impl ::core::default::Default for CAMU_PackageParameterContext { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } -pub type CAMU_PackageParameterContext = Struct_Unnamed17; #[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed18 { - pub camera: u8, - pub context: u8, - pub flip: u8, - pub effect: u8, +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct CAMU_PackageParameterContextDetail { + pub camera: u8_, + pub context: u8_, + pub flip: u8_, + pub effect: u8_, pub width: s16, pub height: s16, pub cropX0: s16, @@ -279,93 +265,87 @@ pub struct Struct_Unnamed18 { pub cropX1: s16, pub cropY1: s16, } -impl ::core::clone::Clone for Struct_Unnamed18 { - fn clone(&self) -> Self { *self } -} -impl ::core::default::Default for Struct_Unnamed18 { +impl ::core::default::Default for CAMU_PackageParameterContextDetail { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } -pub type CAMU_PackageParameterContextDetail = Struct_Unnamed18; - -use services::y2r::Y2RU_StandardCoefficient; extern "C" { pub fn camInit() -> Result; pub fn camExit(); - pub fn CAMU_StartCapture(port: u32) -> Result; - pub fn CAMU_StopCapture(port: u32) -> Result; - pub fn CAMU_IsBusy(busy: *mut u8, port: u32) -> Result; - pub fn CAMU_ClearBuffer(port: u32) -> Result; - pub fn CAMU_GetVsyncInterruptEvent(event: *mut Handle, port: u32) + pub fn CAMU_StartCapture(port: u32_) -> Result; + pub fn CAMU_StopCapture(port: u32_) -> Result; + pub fn CAMU_IsBusy(busy: *mut u8, port: u32_) -> Result; + pub fn CAMU_ClearBuffer(port: u32_) -> Result; + pub fn CAMU_GetVsyncInterruptEvent(event: *mut Handle, port: u32_) + -> Result; + pub fn CAMU_GetBufferErrorInterruptEvent(event: *mut Handle, port: u32_) -> Result; - pub fn CAMU_GetBufferErrorInterruptEvent(event: *mut Handle, port: u32) + pub fn CAMU_SetReceiving(event: *mut Handle, dst: *mut ::libc::c_void, + port: u32_, imageSize: u32_, transferUnit: s16) -> Result; - pub fn CAMU_SetReceiving(event: *mut Handle, - dst: *mut c_void, port: u32, - imageSize: u32, transferUnit: s16) -> Result; - pub fn CAMU_IsFinishedReceiving(finishedReceiving: *mut u8, port: u32) + pub fn CAMU_IsFinishedReceiving(finishedReceiving: *mut u8, port: u32_) -> Result; - pub fn CAMU_SetTransferLines(port: u32, lines: s16, width: s16, + pub fn CAMU_SetTransferLines(port: u32_, lines: s16, width: s16, height: s16) -> Result; pub fn CAMU_GetMaxLines(maxLines: *mut s16, width: s16, height: s16) -> Result; - pub fn CAMU_SetTransferBytes(port: u32, bytes: u32, width: s16, + pub fn CAMU_SetTransferBytes(port: u32_, bytes: u32_, width: s16, height: s16) -> Result; - pub fn CAMU_GetTransferBytes(transferBytes: *mut u32, port: u32) + pub fn CAMU_GetTransferBytes(transferBytes: *mut u32_, port: u32_) -> Result; - pub fn CAMU_GetMaxBytes(maxBytes: *mut u32, width: s16, height: s16) + pub fn CAMU_GetMaxBytes(maxBytes: *mut u32_, width: s16, height: s16) -> Result; - pub fn CAMU_SetTrimming(port: u32, trimming: u8) -> Result; - pub fn CAMU_IsTrimming(trimming: *mut u8, port: u32) -> Result; - pub fn CAMU_SetTrimmingParams(port: u32, xStart: s16, yStart: s16, + pub fn CAMU_SetTrimming(port: u32_, trimming: u8) -> Result; + pub fn CAMU_IsTrimming(trimming: *mut u8, port: u32_) -> Result; + pub fn CAMU_SetTrimmingParams(port: u32_, xStart: s16, yStart: s16, xEnd: s16, yEnd: s16) -> Result; pub fn CAMU_GetTrimmingParams(xStart: *mut s16, yStart: *mut s16, - xEnd: *mut s16, yEnd: *mut s16, port: u32) + xEnd: *mut s16, yEnd: *mut s16, port: u32_) -> Result; - pub fn CAMU_SetTrimmingParamsCenter(port: u32, trimWidth: s16, + pub fn CAMU_SetTrimmingParamsCenter(port: u32_, trimWidth: s16, trimHeight: s16, camWidth: s16, camHeight: s16) -> Result; - pub fn CAMU_Activate(select: u32) -> Result; - pub fn CAMU_SwitchContext(select: u32, context: CAMU_Context) -> Result; - pub fn CAMU_SetExposure(select: u32, exposure: s8) -> Result; - pub fn CAMU_SetWhiteBalance(select: u32, whiteBalance: CAMU_WhiteBalance) + pub fn CAMU_Activate(select: u32_) -> Result; + pub fn CAMU_SwitchContext(select: u32_, context: CAMU_Context) -> Result; + pub fn CAMU_SetExposure(select: u32_, exposure: s8) -> Result; + pub fn CAMU_SetWhiteBalance(select: u32_, whiteBalance: CAMU_WhiteBalance) -> Result; - pub fn CAMU_SetWhiteBalanceWithoutBaseUp(select: u32, + pub fn CAMU_SetWhiteBalanceWithoutBaseUp(select: u32_, whiteBalance: CAMU_WhiteBalance) -> Result; - pub fn CAMU_SetSharpness(select: u32, sharpness: s8) -> Result; - pub fn CAMU_SetAutoExposure(select: u32, autoExposure: u8) -> Result; - pub fn CAMU_IsAutoExposure(autoExposure: *mut u8, select: u32) -> Result; - pub fn CAMU_SetAutoWhiteBalance(select: u32, autoWhiteBalance: u8) + pub fn CAMU_SetSharpness(select: u32_, sharpness: s8) -> Result; + pub fn CAMU_SetAutoExposure(select: u32_, autoExposure: u8) -> Result; + pub fn CAMU_IsAutoExposure(autoExposure: *mut u8, select: u32_) -> Result; + pub fn CAMU_SetAutoWhiteBalance(select: u32_, autoWhiteBalance: u8) -> Result; - pub fn CAMU_IsAutoWhiteBalance(autoWhiteBalance: *mut u8, select: u32) + pub fn CAMU_IsAutoWhiteBalance(autoWhiteBalance: *mut u8, select: u32_) -> Result; - pub fn CAMU_FlipImage(select: u32, flip: CAMU_Flip, + pub fn CAMU_FlipImage(select: u32_, flip: CAMU_Flip, context: CAMU_Context) -> Result; - pub fn CAMU_SetDetailSize(select: u32, width: s16, height: s16, + pub fn CAMU_SetDetailSize(select: u32_, width: s16, height: s16, cropX0: s16, cropY0: s16, cropX1: s16, cropY1: s16, context: CAMU_Context) -> Result; - pub fn CAMU_SetSize(select: u32, size: CAMU_Size, context: CAMU_Context) + pub fn CAMU_SetSize(select: u32_, size: CAMU_Size, context: CAMU_Context) -> Result; - pub fn CAMU_SetFrameRate(select: u32, frameRate: CAMU_FrameRate) + pub fn CAMU_SetFrameRate(select: u32_, frameRate: CAMU_FrameRate) -> Result; - pub fn CAMU_SetPhotoMode(select: u32, photoMode: CAMU_PhotoMode) + pub fn CAMU_SetPhotoMode(select: u32_, photoMode: CAMU_PhotoMode) -> Result; - pub fn CAMU_SetEffect(select: u32, effect: CAMU_Effect, + pub fn CAMU_SetEffect(select: u32_, effect: CAMU_Effect, context: CAMU_Context) -> Result; - pub fn CAMU_SetContrast(select: u32, contrast: CAMU_Contrast) -> Result; - pub fn CAMU_SetLensCorrection(select: u32, + pub fn CAMU_SetContrast(select: u32_, contrast: CAMU_Contrast) -> Result; + pub fn CAMU_SetLensCorrection(select: u32_, lensCorrection: CAMU_LensCorrection) -> Result; - pub fn CAMU_SetOutputFormat(select: u32, format: CAMU_OutputFormat, + pub fn CAMU_SetOutputFormat(select: u32_, format: CAMU_OutputFormat, context: CAMU_Context) -> Result; - pub fn CAMU_SetAutoExposureWindow(select: u32, x: s16, y: s16, + pub fn CAMU_SetAutoExposureWindow(select: u32_, x: s16, y: s16, width: s16, height: s16) -> Result; - pub fn CAMU_SetAutoWhiteBalanceWindow(select: u32, x: s16, y: s16, + pub fn CAMU_SetAutoWhiteBalanceWindow(select: u32_, x: s16, y: s16, width: s16, height: s16) -> Result; - pub fn CAMU_SetNoiseFilter(select: u32, noiseFilter: u8) -> Result; - pub fn CAMU_SynchronizeVsyncTiming(select1: u32, select2: u32) + pub fn CAMU_SetNoiseFilter(select: u32_, noiseFilter: u8) -> Result; + pub fn CAMU_SynchronizeVsyncTiming(select1: u32_, select2: u32_) -> Result; - pub fn CAMU_GetLatestVsyncTiming(timing: *mut s64, port: u32, past: u32) + pub fn CAMU_GetLatestVsyncTiming(timing: *mut s64, port: u32_, past: u32_) -> Result; pub fn CAMU_GetStereoCameraCalibrationData(data: *mut CAMU_StereoCameraCalibrationData) @@ -373,14 +353,14 @@ extern "C" { pub fn CAMU_SetStereoCameraCalibrationData(data: CAMU_StereoCameraCalibrationData) -> Result; - pub fn CAMU_WriteRegisterI2c(select: u32, addr: u16, data: u16) + pub fn CAMU_WriteRegisterI2c(select: u32_, addr: u16_, data: u16_) -> Result; - pub fn CAMU_WriteMcuVariableI2c(select: u32, addr: u16, data: u16) + pub fn CAMU_WriteMcuVariableI2c(select: u32_, addr: u16_, data: u16_) -> Result; - pub fn CAMU_ReadRegisterI2cExclusive(data: *mut u16, select: u32, - addr: u16) -> Result; - pub fn CAMU_ReadMcuVariableI2cExclusive(data: *mut u16, select: u32, - addr: u16) -> Result; + pub fn CAMU_ReadRegisterI2cExclusive(data: *mut u16_, select: u32_, + addr: u16_) -> Result; + pub fn CAMU_ReadMcuVariableI2cExclusive(data: *mut u16_, select: u32_, + addr: u16_) -> Result; pub fn CAMU_SetImageQualityCalibrationData(data: CAMU_ImageQualityCalibrationData) -> Result; @@ -402,9 +382,11 @@ extern "C" { pub fn CAMU_PlayShutterSound(sound: CAMU_ShutterSoundType) -> Result; pub fn CAMU_DriverInitialize() -> Result; pub fn CAMU_DriverFinalize() -> Result; - pub fn CAMU_GetActivatedCamera(select: *mut u32) -> Result; - pub fn CAMU_GetSleepCamera(select: *mut u32) -> Result; - pub fn CAMU_SetSleepCamera(select: u32) -> Result; + pub fn CAMU_GetActivatedCamera(select: *mut u32_) -> Result; + pub fn CAMU_GetSleepCamera(select: *mut u32_) -> Result; + pub fn CAMU_SetSleepCamera(select: u32_) -> Result; pub fn CAMU_SetBrightnessSynchronization(brightnessSynchronization: u8) -> Result; } +use ::types::*; +use super::y2r::*; diff --git a/ctru-sys/src/services/cfgnor.rs b/ctru-sys/src/services/cfgnor.rs index c2c1e44..f85dd02 100644 --- a/ctru-sys/src/services/cfgnor.rs +++ b/ctru-sys/src/services/cfgnor.rs @@ -1,14 +1,19 @@ -use ::Result; +/* automatically generated by rust-bindgen */ +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] extern "C" { - pub fn cfgnorInit(value: u8) -> Result; + pub fn cfgnorInit(value: u8_) -> Result; pub fn cfgnorExit(); - pub fn cfgnorDumpFlash(buf: *mut u32, size: u32) -> Result; - pub fn cfgnorWriteFlash(buf: *mut u32, size: u32) -> Result; - pub fn CFGNOR_Initialize(value: u8) -> Result; + pub fn cfgnorDumpFlash(buf: *mut u32_, size: u32_) -> Result; + pub fn cfgnorWriteFlash(buf: *mut u32_, size: u32_) -> Result; + pub fn CFGNOR_Initialize(value: u8_) -> Result; pub fn CFGNOR_Shutdown() -> Result; - pub fn CFGNOR_ReadData(offset: u32, buf: *mut u32, size: u32) + pub fn CFGNOR_ReadData(offset: u32_, buf: *mut u32_, size: u32_) -> Result; - pub fn CFGNOR_WriteData(offset: u32, buf: *mut u32, size: u32) + pub fn CFGNOR_WriteData(offset: u32_, buf: *mut u32_, size: u32_) -> Result; } +use ::types::*; diff --git a/ctru-sys/src/services/cfgu.rs b/ctru-sys/src/services/cfgu.rs index f1663f0..c4824c2 100644 --- a/ctru-sys/src/services/cfgu.rs +++ b/ctru-sys/src/services/cfgu.rs @@ -1,7 +1,12 @@ -use ::Result; +/* automatically generated by rust-bindgen */ -#[repr(C)] -#[derive(Clone, Copy)] +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] pub enum CFG_Region { CFG_REGION_JPN = 0, CFG_REGION_USA = 1, @@ -11,9 +16,9 @@ pub enum CFG_Region { CFG_REGION_KOR = 5, CFG_REGION_TWN = 6, } - -#[repr(C)] -#[derive(Clone, Copy)] +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] pub enum CFG_Language { CFG_LANGUAGE_JP = 0, CFG_LANGUAGE_EN = 1, @@ -28,19 +33,28 @@ pub enum CFG_Language { CFG_LANGUAGE_RU = 10, CFG_LANGUAGE_TW = 11, } - extern "C" { pub fn cfguInit() -> Result; pub fn cfguExit(); - pub fn CFGU_SecureInfoGetRegion(region: *mut u8) -> Result; - pub fn CFGU_GenHashConsoleUnique(appIDSalt: u32, hash: *mut u64) + pub fn CFGU_SecureInfoGetRegion(region: *mut u8_) -> Result; + pub fn CFGU_GenHashConsoleUnique(appIDSalt: u32_, hash: *mut u64_) + -> Result; + pub fn CFGU_GetRegionCanadaUSA(value: *mut u8_) -> Result; + pub fn CFGU_GetSystemModel(model: *mut u8_) -> Result; + pub fn CFGU_GetModelNintendo2DS(value: *mut u8_) -> Result; + pub fn CFGU_GetCountryCodeString(code: u16_, string: *mut u16_) -> Result; + pub fn CFGU_GetCountryCodeID(string: u16_, code: *mut u16_) -> Result; + pub fn CFGU_GetConfigInfoBlk2(size: u32_, blkID: u32_, outData: *mut u8_) + -> Result; + pub fn CFG_GetConfigInfoBlk4(size: u32_, blkID: u32_, outData: *mut u8_) + -> Result; + pub fn CFG_GetConfigInfoBlk8(size: u32_, blkID: u32_, outData: *mut u8_) + -> Result; + pub fn CFG_SetConfigInfoBlk4(size: u32_, blkID: u32_, inData: *mut u8_) -> Result; - pub fn CFGU_GetRegionCanadaUSA(value: *mut u8) -> Result; - pub fn CFGU_GetSystemModel(model: *mut u8) -> Result; - pub fn CFGU_GetModelNintendo2DS(value: *mut u8) -> Result; - pub fn CFGU_GetCountryCodeString(code: u16, string: *mut u16) -> Result; - pub fn CFGU_GetCountryCodeID(string: u16, code: *mut u16) -> Result; - pub fn CFGU_GetConfigInfoBlk2(size: u32, blkID: u32, outData: *mut u8) + pub fn CFG_SetConfigInfoBlk8(size: u32_, blkID: u32_, inData: *mut u8_) -> Result; - pub fn CFGU_GetSystemLanguage(language: *mut u8) -> Result; + pub fn CFG_UpdateConfigNANDSavegame() -> Result; + pub fn CFGU_GetSystemLanguage(language: *mut u8_) -> Result; } +use ::types::*; diff --git a/ctru-sys/src/services/dsp.rs b/ctru-sys/src/services/dsp.rs index de8241e..fceb935 100644 --- a/ctru-sys/src/services/dsp.rs +++ b/ctru-sys/src/services/dsp.rs @@ -1,48 +1,45 @@ -use ::{Handle, Result}; -use ::libc::c_void; - -#[repr(C)] -#[derive(Clone, Copy)] -pub enum DSP_InterruptType { - DSP_INTERRUPT_PIPE = 2, -} - -#[repr(C)] -#[derive(Clone, Copy)] -pub enum DSP_PipeDirection { - DSP_PIPE_INPUT = 0, - DSP_PIPE_OUTPUT = 1, -} +/* 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 DSP_InterruptType { DSP_INTERRUPT_PIPE = 2, } +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum DSP_PipeDirection { DSP_PIPE_INPUT = 0, DSP_PIPE_OUTPUT = 1, } extern "C" { pub fn dspInit() -> Result; pub fn dspExit(); pub fn DSP_GetHeadphoneStatus(is_inserted: *mut u8) -> Result; - pub fn DSP_FlushDataCache(address: *const c_void, - size: u32) -> Result; - pub fn DSP_InvalidateDataCache(address: *const c_void, - size: u32) -> Result; + pub fn DSP_FlushDataCache(address: *const ::libc::c_void, size: u32_) + -> Result; + pub fn DSP_InvalidateDataCache(address: *const ::libc::c_void, size: u32_) + -> Result; pub fn DSP_GetSemaphoreHandle(semaphore: *mut Handle) -> Result; - pub fn DSP_SetSemaphore(value: u16) -> Result; - pub fn DSP_SetSemaphoreMask(mask: u16) -> Result; - pub fn DSP_LoadComponent(component: *const c_void, - size: u32, prog_mask: u16, data_mask: u16, + pub fn DSP_SetSemaphore(value: u16_) -> Result; + pub fn DSP_SetSemaphoreMask(mask: u16_) -> Result; + pub fn DSP_LoadComponent(component: *const ::libc::c_void, size: u32_, + prog_mask: u16_, data_mask: u16_, is_loaded: *mut u8) -> Result; pub fn DSP_UnloadComponent() -> Result; - pub fn DSP_RegisterInterruptEvents(handle: Handle, interrupt: u32, - channel: u32) -> Result; - pub fn DSP_ReadPipeIfPossible(channel: u32, peer: u32, - buffer: *mut c_void, - length: u16, length_read: *mut u16) - -> Result; - pub fn DSP_WriteProcessPipe(channel: u32, - buffer: *const c_void, - length: u32) -> Result; - pub fn DSP_ConvertProcessAddressFromDspDram(dsp_address: u32, - arm_address: *mut u32) + pub fn DSP_RegisterInterruptEvents(handle: Handle, interrupt: u32_, + channel: u32_) -> Result; + pub fn DSP_ReadPipeIfPossible(channel: u32_, peer: u32_, + buffer: *mut ::libc::c_void, length: u16_, + length_read: *mut u16_) -> Result; + pub fn DSP_WriteProcessPipe(channel: u32_, buffer: *const ::libc::c_void, + length: u32_) -> Result; + pub fn DSP_ConvertProcessAddressFromDspDram(dsp_address: u32_, + arm_address: *mut u32_) -> Result; - pub fn DSP_RecvData(regNo: u16, value: *mut u16) -> Result; - pub fn DSP_RecvDataIsReady(regNo: u16, is_ready: *mut u8) -> Result; - pub fn DSP_SendData(regNo: u16, value: u16) -> Result; - pub fn DSP_SendDataIsEmpty(regNo: u16, is_empty: *mut u8) -> Result; + pub fn DSP_RecvData(regNo: u16_, value: *mut u16_) -> Result; + pub fn DSP_RecvDataIsReady(regNo: u16_, is_ready: *mut u8) -> Result; + pub fn DSP_SendData(regNo: u16_, value: u16_) -> Result; + pub fn DSP_SendDataIsEmpty(regNo: u16_, is_empty: *mut u8) -> Result; } +use ::types::*; diff --git a/ctru-sys/src/services/fs.rs b/ctru-sys/src/services/fs.rs index 421bbcb..c94c2b6 100644 --- a/ctru-sys/src/services/fs.rs +++ b/ctru-sys/src/services/fs.rs @@ -4,21 +4,27 @@ non_camel_case_types, non_upper_case_globals, non_snake_case)] - -use ::{Handle, Result}; - -pub const FS_OPEN_READ: u32 = 1; -pub const FS_OPEN_WRITE: u32 = 2; -pub const FS_OPEN_CREATE: u32 = 4; - -pub const FS_WRITE_FLUSH: u32 = 1; -pub const FS_WRITE_UPDATE_TIME: u32 = 256; - -pub const FS_ATTRIBUTE_DIRECTORY: u32 = 1; -pub const FS_ATTRIBUTE_HIDDEN: u32 = 256; -pub const FS_ATTRIBUTE_ARCHIVE: u32 = 65536; -pub const FS_ATTRIBUTE_READ_ONLY: u32 = 16777216; - +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum Enum_Unnamed1 { + FS_OPEN_READ = 1, + FS_OPEN_WRITE = 2, + FS_OPEN_CREATE = 4, +} +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum Enum_Unnamed2 { FS_WRITE_FLUSH = 1, FS_WRITE_UPDATE_TIME = 256, } +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum Enum_Unnamed3 { + FS_ATTRIBUTE_DIRECTORY = 1, + FS_ATTRIBUTE_HIDDEN = 256, + FS_ATTRIBUTE_ARCHIVE = 65536, + FS_ATTRIBUTE_READ_ONLY = 16777216, +} #[derive(Copy, Clone)] #[repr(u32)] #[derive(Debug)] @@ -135,13 +141,13 @@ pub enum FS_DirectoryAction { DIRECTORY_ACTION_UNKNOWN = 0, } #[repr(C)] #[derive(Copy)] pub struct FS_DirectoryEntry { - pub name: [u16; 262usize], - pub shortName: [u8; 10usize], - pub shortExt: [u8; 4usize], - pub valid: u8, - pub reserved: u8, - pub attributes: u32, - pub fileSize: u64, + pub name: [u16_; 262usize], + pub shortName: [::libc::c_char; 10usize], + pub shortExt: [::libc::c_char; 4usize], + pub valid: u8_, + pub reserved: u8_, + pub attributes: u32_, + pub fileSize: u64_, } impl ::core::clone::Clone for FS_DirectoryEntry { fn clone(&self) -> Self { *self } @@ -153,10 +159,10 @@ impl ::core::default::Default for FS_DirectoryEntry { #[derive(Copy, Clone)] #[derive(Debug)] pub struct FS_ArchiveResource { - pub sectorSize: u32, - pub clusterSize: u32, - pub totalClusters: u32, - pub freeClusters: u32, + pub sectorSize: u32_, + pub clusterSize: u32_, + pub totalClusters: u32_, + pub freeClusters: u32_, } impl ::core::default::Default for FS_ArchiveResource { fn default() -> Self { unsafe { ::core::mem::zeroed() } } @@ -165,9 +171,9 @@ impl ::core::default::Default for FS_ArchiveResource { #[derive(Copy, Clone)] #[derive(Debug)] pub struct FS_ProgramInfo { - pub programId: u64, + pub programId: u64_, pub _bindgen_bitfield_1_: FS_MediaType, - pub padding: [u8; 7usize], + pub padding: [u8_; 7usize], } impl ::core::default::Default for FS_ProgramInfo { fn default() -> Self { unsafe { ::core::mem::zeroed() } } @@ -176,9 +182,9 @@ impl ::core::default::Default for FS_ProgramInfo { #[derive(Copy, Clone)] #[derive(Debug)] pub struct FS_ProductInfo { - pub productCode: [u8; 16usize], - pub companyCode: [u8; 2usize], - pub remasterVersion: u16, + pub productCode: [::libc::c_char; 16usize], + pub companyCode: [::libc::c_char; 2usize], + pub remasterVersion: u16_, } impl ::core::default::Default for FS_ProductInfo { fn default() -> Self { unsafe { ::core::mem::zeroed() } } @@ -186,8 +192,8 @@ impl ::core::default::Default for FS_ProductInfo { #[repr(C)] #[derive(Copy)] pub struct FS_IntegrityVerificationSeed { - pub aesCbcMac: [u8; 16usize], - pub movableSed: [u8; 288usize], + pub aesCbcMac: [u8_; 16usize], + pub movableSed: [u8_; 288usize], } impl ::core::clone::Clone for FS_IntegrityVerificationSeed { fn clone(&self) -> Self { *self } @@ -200,10 +206,10 @@ impl ::core::default::Default for FS_IntegrityVerificationSeed { #[derive(Debug)] pub struct FS_ExtSaveDataInfo { pub _bindgen_bitfield_1_: FS_MediaType, - pub unknown: u8, - pub reserved1: u16, - pub saveId: u64, - pub reserved2: u32, + pub unknown: u8_, + pub reserved1: u16_, + pub saveId: u64_, + pub reserved2: u32_, } impl ::core::default::Default for FS_ExtSaveDataInfo { fn default() -> Self { unsafe { ::core::mem::zeroed() } } @@ -213,9 +219,9 @@ impl ::core::default::Default for FS_ExtSaveDataInfo { #[derive(Debug)] pub struct FS_SystemSaveDataInfo { pub _bindgen_bitfield_1_: FS_MediaType, - pub unknown: u8, - pub reserved: u16, - pub saveId: u32, + pub unknown: u8_, + pub reserved: u16_, + pub saveId: u32_, } impl ::core::default::Default for FS_SystemSaveDataInfo { fn default() -> Self { unsafe { ::core::mem::zeroed() } } @@ -224,8 +230,8 @@ impl ::core::default::Default for FS_SystemSaveDataInfo { #[derive(Copy, Clone)] #[derive(Debug)] pub struct FS_DeviceMoveContext { - pub ivs: [u8; 16usize], - pub encryptParameter: [u8; 16usize], + pub ivs: [u8_; 16usize], + pub encryptParameter: [u8_; 16usize], } impl ::core::default::Default for FS_DeviceMoveContext { fn default() -> Self { unsafe { ::core::mem::zeroed() } } @@ -235,27 +241,27 @@ impl ::core::default::Default for FS_DeviceMoveContext { #[derive(Debug)] pub struct FS_Path { pub type_: FS_PathType, - pub size: u32, + pub size: u32_, pub data: *const ::libc::c_void, } impl ::core::default::Default for FS_Path { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } -pub type FS_Archive = u64; +pub type FS_Archive = u64_; #[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, + 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() } } @@ -264,13 +270,13 @@ impl ::core::default::Default for romfs_header { #[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], + 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() } } @@ -279,13 +285,13 @@ impl ::core::default::Default for romfs_dir { #[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], + 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() } } @@ -302,15 +308,15 @@ extern "C" { -> FS_Path; pub fn fsGetSessionHandle() -> *mut Handle; pub fn FSUSER_Control(action: FS_Action, input: *mut ::libc::c_void, - inputSize: u32, output: *mut ::libc::c_void, - outputSize: u32) -> Result; + inputSize: u32_, output: *mut ::libc::c_void, + outputSize: u32_) -> Result; pub fn FSUSER_Initialize(session: Handle) -> Result; pub fn FSUSER_OpenFile(out: *mut Handle, archive: FS_Archive, - path: FS_Path, openFlags: u32, attributes: u32) + path: FS_Path, openFlags: u32_, attributes: u32_) -> Result; pub fn FSUSER_OpenFileDirectly(out: *mut Handle, archiveId: FS_ArchiveID, archivePath: FS_Path, filePath: FS_Path, - openFlags: u32, attributes: u32) + openFlags: u32_, attributes: u32_) -> Result; pub fn FSUSER_DeleteFile(archive: FS_Archive, path: FS_Path) -> Result; pub fn FSUSER_RenameFile(srcArchive: FS_Archive, srcPath: FS_Path, @@ -321,9 +327,9 @@ extern "C" { pub fn FSUSER_DeleteDirectoryRecursively(archive: FS_Archive, path: FS_Path) -> Result; pub fn FSUSER_CreateFile(archive: FS_Archive, path: FS_Path, - attributes: u32, fileSize: u64) -> Result; + attributes: u32_, fileSize: u64_) -> Result; pub fn FSUSER_CreateDirectory(archive: FS_Archive, path: FS_Path, - attributes: u32) -> Result; + attributes: u32_) -> Result; pub fn FSUSER_RenameDirectory(srcArchive: FS_Archive, srcPath: FS_Path, dstArchive: FS_Archive, dstPath: FS_Path) -> Result; @@ -333,11 +339,11 @@ extern "C" { path: FS_Path) -> Result; pub fn FSUSER_ControlArchive(archive: FS_Archive, action: FS_ArchiveAction, - input: *mut ::libc::c_void, inputSize: u32, + input: *mut ::libc::c_void, inputSize: u32_, output: *mut ::libc::c_void, - outputSize: u32) -> Result; + outputSize: u32_) -> Result; pub fn FSUSER_CloseArchive(archive: FS_Archive) -> Result; - pub fn FSUSER_GetFreeBytes(freeBytes: *mut u64, archive: FS_Archive) + pub fn FSUSER_GetFreeBytes(freeBytes: *mut u64_, archive: FS_Archive) -> Result; pub fn FSUSER_GetCardType(type_: *mut FS_CardType) -> Result; pub fn FSUSER_GetSdmcArchiveResource(archiveResource: @@ -346,82 +352,82 @@ extern "C" { pub fn FSUSER_GetNandArchiveResource(archiveResource: *mut FS_ArchiveResource) -> Result; - pub fn FSUSER_GetSdmcFatfsError(error: *mut u32) -> Result; + pub fn FSUSER_GetSdmcFatfsError(error: *mut u32_) -> Result; pub fn FSUSER_IsSdmcDetected(detected: *mut u8) -> Result; pub fn FSUSER_IsSdmcWritable(writable: *mut u8) -> Result; - pub fn FSUSER_GetSdmcCid(out: *mut u8, length: u32) -> Result; - pub fn FSUSER_GetNandCid(out: *mut u8, length: u32) -> Result; - pub fn FSUSER_GetSdmcSpeedInfo(speedInfo: *mut u32) -> Result; - pub fn FSUSER_GetNandSpeedInfo(speedInfo: *mut u32) -> Result; - pub fn FSUSER_GetSdmcLog(out: *mut u8, length: u32) -> Result; - pub fn FSUSER_GetNandLog(out: *mut u8, length: u32) -> Result; + pub fn FSUSER_GetSdmcCid(out: *mut u8_, length: u32_) -> Result; + pub fn FSUSER_GetNandCid(out: *mut u8_, length: u32_) -> Result; + pub fn FSUSER_GetSdmcSpeedInfo(speedInfo: *mut u32_) -> Result; + pub fn FSUSER_GetNandSpeedInfo(speedInfo: *mut u32_) -> Result; + pub fn FSUSER_GetSdmcLog(out: *mut u8_, length: u32_) -> Result; + pub fn FSUSER_GetNandLog(out: *mut u8_, length: u32_) -> Result; pub fn FSUSER_ClearSdmcLog() -> Result; pub fn FSUSER_ClearNandLog() -> Result; pub fn FSUSER_CardSlotIsInserted(inserted: *mut u8) -> Result; pub fn FSUSER_CardSlotPowerOn(status: *mut u8) -> Result; pub fn FSUSER_CardSlotPowerOff(status: *mut u8) -> Result; pub fn FSUSER_CardSlotGetCardIFPowerStatus(status: *mut u8) -> Result; - pub fn FSUSER_CardNorDirectCommand(commandId: u8) -> Result; - pub fn FSUSER_CardNorDirectCommandWithAddress(commandId: u8, - address: u32) -> Result; - pub fn FSUSER_CardNorDirectRead(commandId: u8, size: u32, - output: *mut u8) -> Result; - pub fn FSUSER_CardNorDirectReadWithAddress(commandId: u8, address: u32, - size: u32, output: *mut u8) + pub fn FSUSER_CardNorDirectCommand(commandId: u8_) -> Result; + pub fn FSUSER_CardNorDirectCommandWithAddress(commandId: u8_, + address: u32_) -> Result; + pub fn FSUSER_CardNorDirectRead(commandId: u8_, size: u32_, + output: *mut u8_) -> Result; + pub fn FSUSER_CardNorDirectReadWithAddress(commandId: u8_, address: u32_, + size: u32_, output: *mut u8_) -> Result; - pub fn FSUSER_CardNorDirectWrite(commandId: u8, size: u32, - input: *mut u8) -> Result; - pub fn FSUSER_CardNorDirectWriteWithAddress(commandId: u8, address: u32, - size: u32, input: *mut u8) + pub fn FSUSER_CardNorDirectWrite(commandId: u8_, size: u32_, + input: *mut u8_) -> Result; + pub fn FSUSER_CardNorDirectWriteWithAddress(commandId: u8_, address: u32_, + size: u32_, input: *mut u8_) -> Result; - pub fn FSUSER_CardNorDirectRead_4xIO(commandId: u8, address: u32, - size: u32, output: *mut u8) + pub fn FSUSER_CardNorDirectRead_4xIO(commandId: u8_, address: u32_, + size: u32_, output: *mut u8_) -> Result; - pub fn FSUSER_CardNorDirectCpuWriteWithoutVerify(address: u32, - size: u32, - input: *mut u8) + pub fn FSUSER_CardNorDirectCpuWriteWithoutVerify(address: u32_, + size: u32_, + input: *mut u8_) -> Result; - pub fn FSUSER_CardNorDirectSectorEraseWithoutVerify(address: u32) + pub fn FSUSER_CardNorDirectSectorEraseWithoutVerify(address: u32_) -> Result; - pub fn FSUSER_GetProductInfo(info: *mut FS_ProductInfo, processId: u32) + pub fn FSUSER_GetProductInfo(info: *mut FS_ProductInfo, processId: u32_) -> Result; pub fn FSUSER_GetProgramLaunchInfo(info: *mut FS_ProgramInfo, - processId: u32) -> Result; + processId: u32_) -> Result; pub fn FSUSER_SetCardSpiBaudRate(baudRate: FS_CardSpiBaudRate) -> Result; pub fn FSUSER_SetCardSpiBusMode(busMode: FS_CardSpiBusMode) -> Result; pub fn FSUSER_SendInitializeInfoTo9() -> Result; - pub fn FSUSER_GetSpecialContentIndex(index: *mut u16, + pub fn FSUSER_GetSpecialContentIndex(index: *mut u16_, mediaType: FS_MediaType, - programId: u64, + programId: u64_, type_: FS_SpecialContentType) -> Result; - pub fn FSUSER_GetLegacyRomHeader(mediaType: FS_MediaType, programId: u64, - header: *mut u8) -> Result; + pub fn FSUSER_GetLegacyRomHeader(mediaType: FS_MediaType, programId: u64_, + header: *mut u8_) -> Result; pub fn FSUSER_GetLegacyBannerData(mediaType: FS_MediaType, - programId: u64, banner: *mut u8) + programId: u64_, banner: *mut u8_) -> Result; pub fn FSUSER_CheckAuthorityToAccessExtSaveData(access: *mut u8, mediaType: FS_MediaType, - saveId: u64, - processId: u32) + saveId: u64_, + processId: u32_) -> Result; - pub fn FSUSER_QueryTotalQuotaSize(quotaSize: *mut u64, directories: u32, - files: u32, fileSizeCount: u32, - fileSizes: *mut u64) -> Result; - pub fn FSUSER_AbnegateAccessRight(accessRight: u32) -> Result; + pub fn FSUSER_QueryTotalQuotaSize(quotaSize: *mut u64_, directories: u32_, + files: u32_, fileSizeCount: u32_, + fileSizes: *mut u64_) -> Result; + pub fn FSUSER_AbnegateAccessRight(accessRight: u32_) -> Result; pub fn FSUSER_DeleteSdmcRoot() -> Result; pub fn FSUSER_DeleteAllExtSaveDataOnNand() -> Result; pub fn FSUSER_InitializeCtrFileSystem() -> Result; pub fn FSUSER_CreateSeed() -> Result; - pub fn FSUSER_GetFormatInfo(totalSize: *mut u32, directories: *mut u32, - files: *mut u32, duplicateData: *mut u8, + pub fn FSUSER_GetFormatInfo(totalSize: *mut u32_, directories: *mut u32_, + files: *mut u32_, duplicateData: *mut u8, archiveId: FS_ArchiveID, path: FS_Path) -> Result; - pub fn FSUSER_GetLegacyRomHeader2(headerSize: u32, + pub fn FSUSER_GetLegacyRomHeader2(headerSize: u32_, mediaType: FS_MediaType, - programId: u64, header: *mut u8) + programId: u64_, header: *mut u8_) -> Result; - pub fn FSUSER_GetSdmcCtrRootPath(out: *mut u8, length: u32) -> Result; + pub fn FSUSER_GetSdmcCtrRootPath(out: *mut u8_, length: u32_) -> Result; pub fn FSUSER_GetArchiveResource(archiveResource: *mut FS_ArchiveResource, mediaType: FS_SystemMediaType) -> Result; pub fn FSUSER_ExportIntegrityVerificationSeed(seed: @@ -431,106 +437,111 @@ extern "C" { *mut FS_IntegrityVerificationSeed) -> Result; pub fn FSUSER_FormatSaveData(archiveId: FS_ArchiveID, path: FS_Path, - blocks: u32, directories: u32, files: u32, - directoryBuckets: u32, fileBuckets: u32, + blocks: u32_, directories: u32_, files: u32_, + directoryBuckets: u32_, fileBuckets: u32_, duplicateData: u8) -> Result; - pub fn FSUSER_GetLegacySubBannerData(bannerSize: u32, + pub fn FSUSER_GetLegacySubBannerData(bannerSize: u32_, mediaType: FS_MediaType, - programId: u64, banner: *mut u8) + programId: u64_, banner: *mut u8_) -> Result; - pub fn FSUSER_ReadSpecialFile(bytesRead: *mut u32, fileOffset: u64, - size: u32, data: *mut u8) -> Result; - pub fn FSUSER_GetSpecialFileSize(fileSize: *mut u64) -> Result; + pub fn FSUSER_UpdateSha256Context(data: *const ::libc::c_void, + inputSize: u32_, hash: *mut u8_) + -> Result; + pub fn FSUSER_ReadSpecialFile(bytesRead: *mut u32_, fileOffset: u64_, + size: u32_, data: *mut u8_) -> Result; + pub fn FSUSER_GetSpecialFileSize(fileSize: *mut u64_) -> Result; pub fn FSUSER_CreateExtSaveData(info: FS_ExtSaveDataInfo, - directories: u32, files: u32, - sizeLimit: u64, smdhSize: u32, - smdh: *mut u8) -> Result; + directories: u32_, files: u32_, + sizeLimit: u64_, smdhSize: u32_, + smdh: *mut u8_) -> Result; pub fn FSUSER_DeleteExtSaveData(info: FS_ExtSaveDataInfo) -> Result; - pub fn FSUSER_ReadExtSaveDataIcon(bytesRead: *mut u32, + pub fn FSUSER_ReadExtSaveDataIcon(bytesRead: *mut u32_, info: FS_ExtSaveDataInfo, - smdhSize: u32, smdh: *mut u8) + smdhSize: u32_, smdh: *mut u8_) -> Result; - pub fn FSUSER_GetExtDataBlockSize(totalBlocks: *mut u64, - freeBlocks: *mut u64, - blockSize: *mut u32, + pub fn FSUSER_GetExtDataBlockSize(totalBlocks: *mut u64_, + freeBlocks: *mut u64_, + blockSize: *mut u32_, info: FS_ExtSaveDataInfo) -> Result; - pub fn FSUSER_EnumerateExtSaveData(idsWritten: *mut u32, idsSize: u32, - mediaType: FS_MediaType, idSize: u32, - shared: u8, ids: *mut u8) -> Result; + pub fn FSUSER_EnumerateExtSaveData(idsWritten: *mut u32_, idsSize: u32_, + mediaType: FS_MediaType, idSize: u32_, + shared: u8, ids: *mut u8_) -> Result; pub fn FSUSER_CreateSystemSaveData(info: FS_SystemSaveDataInfo, - totalSize: u32, blockSize: u32, - directories: u32, files: u32, - directoryBuckets: u32, - fileBuckets: u32, duplicateData: u8) + totalSize: u32_, blockSize: u32_, + directories: u32_, files: u32_, + directoryBuckets: u32_, + fileBuckets: u32_, duplicateData: u8) -> Result; pub fn FSUSER_DeleteSystemSaveData(info: FS_SystemSaveDataInfo) -> Result; pub fn FSUSER_StartDeviceMoveAsSource(context: *mut FS_DeviceMoveContext) -> Result; pub fn FSUSER_StartDeviceMoveAsDestination(context: FS_DeviceMoveContext, clear: u8) -> Result; - pub fn FSUSER_SetArchivePriority(archive: FS_Archive, priority: u32) + pub fn FSUSER_SetArchivePriority(archive: FS_Archive, priority: u32_) -> Result; - pub fn FSUSER_GetArchivePriority(priority: *mut u32, archive: FS_Archive) + pub fn FSUSER_GetArchivePriority(priority: *mut u32_, archive: FS_Archive) -> Result; - pub fn FSUSER_SetCtrCardLatencyParameter(latency: u64, + pub fn FSUSER_SetCtrCardLatencyParameter(latency: u64_, emulateEndurance: u8) -> Result; pub fn FSUSER_SwitchCleanupInvalidSaveData(enable: u8) -> Result; - pub fn FSUSER_EnumerateSystemSaveData(idsWritten: *mut u32, - idsSize: u32, ids: *mut u32) + pub fn FSUSER_EnumerateSystemSaveData(idsWritten: *mut u32_, + idsSize: u32_, ids: *mut u32_) -> Result; - pub fn FSUSER_InitializeWithSdkVersion(session: Handle, version: u32) + pub fn FSUSER_InitializeWithSdkVersion(session: Handle, version: u32_) -> Result; - pub fn FSUSER_SetPriority(priority: u32) -> Result; - pub fn FSUSER_GetPriority(priority: *mut u32) -> Result; - pub fn FSUSER_SetSaveDataSecureValue(value: u64, + pub fn FSUSER_SetPriority(priority: u32_) -> Result; + pub fn FSUSER_GetPriority(priority: *mut u32_) -> Result; + pub fn FSUSER_SetSaveDataSecureValue(value: u64_, slot: FS_SecureValueSlot, - titleUniqueId: u32, - titleVariation: u8) -> Result; - pub fn FSUSER_GetSaveDataSecureValue(exists: *mut u8, value: *mut u64, + titleUniqueId: u32_, + titleVariation: u8_) -> Result; + pub fn FSUSER_GetSaveDataSecureValue(exists: *mut u8, value: *mut u64_, slot: FS_SecureValueSlot, - titleUniqueId: u32, - titleVariation: u8) -> Result; + titleUniqueId: u32_, + titleVariation: u8_) -> Result; pub fn FSUSER_ControlSecureSave(action: FS_SecureSaveAction, input: *mut ::libc::c_void, - inputSize: u32, + inputSize: u32_, output: *mut ::libc::c_void, - outputSize: u32) -> Result; + outputSize: u32_) -> Result; pub fn FSUSER_GetMediaType(mediaType: *mut FS_MediaType) -> Result; pub fn FSFILE_Control(handle: Handle, action: FS_FileAction, - input: *mut ::libc::c_void, inputSize: u32, - output: *mut ::libc::c_void, outputSize: u32) + input: *mut ::libc::c_void, inputSize: u32_, + output: *mut ::libc::c_void, outputSize: u32_) -> Result; pub fn FSFILE_OpenSubFile(handle: Handle, subFile: *mut Handle, - offset: u64, size: u64) -> Result; - pub fn FSFILE_Read(handle: Handle, bytesRead: *mut u32, offset: u64, - buffer: *mut ::libc::c_void, size: u32) -> Result; - pub fn FSFILE_Write(handle: Handle, bytesWritten: *mut u32, offset: u64, - buffer: *const ::libc::c_void, size: u32, - flags: u32) -> Result; - pub fn FSFILE_GetSize(handle: Handle, size: *mut u64) -> Result; - pub fn FSFILE_SetSize(handle: Handle, size: u64) -> Result; - pub fn FSFILE_GetAttributes(handle: Handle, attributes: *mut u32) - -> Result; - pub fn FSFILE_SetAttributes(handle: Handle, attributes: u32) -> Result; + offset: u64_, size: u64_) -> Result; + pub fn FSFILE_Read(handle: Handle, bytesRead: *mut u32_, offset: u64_, + buffer: *mut ::libc::c_void, size: u32_) -> Result; + pub fn FSFILE_Write(handle: Handle, bytesWritten: *mut u32_, offset: u64_, + buffer: *const ::libc::c_void, size: u32_, + flags: u32_) -> Result; + pub fn FSFILE_GetSize(handle: Handle, size: *mut u64_) -> Result; + pub fn FSFILE_SetSize(handle: Handle, size: u64_) -> Result; + pub fn FSFILE_GetAttributes(handle: Handle, attributes: *mut u32_) + -> Result; + pub fn FSFILE_SetAttributes(handle: Handle, attributes: u32_) -> Result; pub fn FSFILE_Close(handle: Handle) -> Result; pub fn FSFILE_Flush(handle: Handle) -> Result; - pub fn FSFILE_SetPriority(handle: Handle, priority: u32) -> Result; - pub fn FSFILE_GetPriority(handle: Handle, priority: *mut u32) -> Result; + pub fn FSFILE_SetPriority(handle: Handle, priority: u32_) -> Result; + pub fn FSFILE_GetPriority(handle: Handle, priority: *mut u32_) -> Result; pub fn FSFILE_OpenLinkFile(handle: Handle, linkFile: *mut Handle) -> Result; pub fn FSDIR_Control(handle: Handle, action: FS_DirectoryAction, - input: *mut ::libc::c_void, inputSize: u32, - output: *mut ::libc::c_void, outputSize: u32) + input: *mut ::libc::c_void, inputSize: u32_, + output: *mut ::libc::c_void, outputSize: u32_) -> Result; - pub fn FSDIR_Read(handle: Handle, entriesRead: *mut u32, - entryCount: u32, entries: *mut FS_DirectoryEntry) + pub fn FSDIR_Read(handle: Handle, entriesRead: *mut u32_, + entryCount: u32_, entries: *mut FS_DirectoryEntry) -> Result; pub fn FSDIR_Close(handle: Handle) -> Result; - pub fn FSDIR_SetPriority(handle: Handle, priority: u32) -> Result; - pub fn FSDIR_GetPriority(handle: Handle, priority: *mut u32) -> Result; + pub fn FSDIR_SetPriority(handle: Handle, priority: u32_) -> Result; + pub fn FSDIR_GetPriority(handle: Handle, priority: *mut u32_) -> Result; pub fn romfsMount(mount: *mut *mut romfs_mount) -> Result; - pub fn romfsMountFromFile(file: Handle, offset: u32, + 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/services/gspgpu.rs b/ctru-sys/src/services/gspgpu.rs index ffe4703..0b76304 100644 --- a/ctru-sys/src/services/gspgpu.rs +++ b/ctru-sys/src/services/gspgpu.rs @@ -1,32 +1,27 @@ -use ::{Handle, Result}; -use ::libc::c_void; -use ::types::*; - -#[inline] -pub fn GSPGPU_REBASE_REG(r: u32) { - ((r)-0x1EB00000); -} +/* automatically generated by rust-bindgen */ +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] #[repr(C)] -#[derive(Copy)] +#[derive(Copy, Clone)] +#[derive(Debug)] pub struct GSPGPU_FramebufferInfo { - pub active_framebuf: u32, - pub framebuf0_vaddr: *mut u32, - pub framebuf1_vaddr: *mut u32, - pub framebuf_widthbytesize: u32, - pub format: u32, - pub framebuf_dispselect: u32, - pub unk: u32, -} -impl ::core::clone::Clone for GSPGPU_FramebufferInfo { - fn clone(&self) -> Self { *self } + pub active_framebuf: u32_, + pub framebuf0_vaddr: *mut u32_, + pub framebuf1_vaddr: *mut u32_, + pub framebuf_widthbytesize: u32_, + pub format: u32_, + pub framebuf_dispselect: u32_, + pub unk: u32_, } impl ::core::default::Default for GSPGPU_FramebufferInfo { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } - -#[derive(Clone, Copy)] -#[repr(C)] +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] pub enum GSPGPU_FramebufferFormats { GSP_RGBA8_OES = 0, GSP_BGR8_OES = 1, @@ -34,35 +29,30 @@ pub enum GSPGPU_FramebufferFormats { GSP_RGB5_A1_OES = 3, GSP_RGBA4_OES = 4, } - #[repr(C)] -#[derive(Copy)] +#[derive(Copy, Clone)] +#[derive(Debug)] pub struct GSPGPU_CaptureInfoEntry { - pub framebuf0_vaddr: *mut u32, - pub framebuf1_vaddr: *mut u32, - pub format: u32, - pub framebuf_widthbytesize: u32, -} -impl ::core::clone::Clone for GSPGPU_CaptureInfoEntry { - fn clone(&self) -> Self { *self } + pub framebuf0_vaddr: *mut u32_, + pub framebuf1_vaddr: *mut u32_, + pub format: u32_, + pub framebuf_widthbytesize: u32_, } impl ::core::default::Default for GSPGPU_CaptureInfoEntry { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } - #[repr(C)] -#[derive(Copy)] +#[derive(Copy, Clone)] +#[derive(Debug)] pub struct GSPGPU_CaptureInfo { pub screencapture: [GSPGPU_CaptureInfoEntry; 2usize], } -impl ::core::clone::Clone for GSPGPU_CaptureInfo { - fn clone(&self) -> Self { *self } -} impl ::core::default::Default for GSPGPU_CaptureInfo { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } - -#[repr(C)] +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] pub enum GSPGPU_Event { GSPGPU_EVENT_PSC0 = 0, GSPGPU_EVENT_PSC1 = 1, @@ -73,48 +63,45 @@ pub enum GSPGPU_Event { GSPGPU_EVENT_DMA = 6, GSPGPU_EVENT_MAX = 7, } - -use ThreadFunc; - extern "C" { pub fn gspInit() -> Result; pub fn gspExit(); pub fn gspSetEventCallback(id: GSPGPU_Event, cb: ThreadFunc, - data: *mut c_void, - oneShot: u8); + data: *mut ::libc::c_void, oneShot: u8); pub fn gspInitEventHandler(gspEvent: Handle, gspSharedMem: *mut vu8, - gspThreadId: u8) -> Result; + gspThreadId: u8_) -> Result; pub fn gspExitEventHandler(); pub fn gspWaitForEvent(id: GSPGPU_Event, nextEvent: u8); pub fn gspWaitForAnyEvent() -> GSPGPU_Event; - pub fn gspSubmitGxCommand(sharedGspCmdBuf: *mut u32, - gxCommand: *mut u32) -> Result; - pub fn GSPGPU_AcquireRight(flags: u8) -> Result; + pub fn gspSubmitGxCommand(sharedGspCmdBuf: *mut u32_, + gxCommand: *mut u32_) -> Result; + pub fn GSPGPU_AcquireRight(flags: u8_) -> Result; pub fn GSPGPU_ReleaseRight() -> Result; pub fn GSPGPU_ImportDisplayCaptureInfo(captureinfo: *mut GSPGPU_CaptureInfo) -> Result; pub fn GSPGPU_SaveVramSysArea() -> Result; pub fn GSPGPU_RestoreVramSysArea() -> Result; - pub fn GSPGPU_SetLcdForceBlack(flags: u8) -> Result; - pub fn GSPGPU_SetBufferSwap(screenid: u32, + pub fn GSPGPU_SetLcdForceBlack(flags: u8_) -> Result; + pub fn GSPGPU_SetBufferSwap(screenid: u32_, framebufinfo: *mut GSPGPU_FramebufferInfo) -> Result; - pub fn GSPGPU_FlushDataCache(adr: *const c_void, - size: u32) -> Result; - pub fn GSPGPU_InvalidateDataCache(adr: *const c_void, - size: u32) -> Result; - pub fn GSPGPU_WriteHWRegs(regAddr: u32, data: *mut u32, size: u8) + pub fn GSPGPU_FlushDataCache(adr: *const ::libc::c_void, size: u32_) + -> Result; + pub fn GSPGPU_InvalidateDataCache(adr: *const ::libc::c_void, size: u32_) -> Result; - pub fn GSPGPU_WriteHWRegsWithMask(regAddr: u32, data: *mut u32, - datasize: u8, maskdata: *mut u32, - masksize: u8) -> Result; - pub fn GSPGPU_ReadHWRegs(regAddr: u32, data: *mut u32, size: u8) + pub fn GSPGPU_WriteHWRegs(regAddr: u32_, data: *mut u32_, size: u8_) + -> Result; + pub fn GSPGPU_WriteHWRegsWithMask(regAddr: u32_, data: *mut u32_, + datasize: u8_, maskdata: *mut u32_, + masksize: u8_) -> Result; + pub fn GSPGPU_ReadHWRegs(regAddr: u32_, data: *mut u32_, size: u8_) -> Result; pub fn GSPGPU_RegisterInterruptRelayQueue(eventHandle: Handle, - flags: u32, + flags: u32_, outMemHandle: *mut Handle, - threadID: *mut u8) -> Result; + threadID: *mut u8_) -> Result; pub fn GSPGPU_UnregisterInterruptRelayQueue() -> Result; pub fn GSPGPU_TriggerCmdReqQueue() -> Result; } +use ::types::*; diff --git a/ctru-sys/src/services/gsplcd.rs b/ctru-sys/src/services/gsplcd.rs index 332ebef..5d9188e 100644 --- a/ctru-sys/src/services/gsplcd.rs +++ b/ctru-sys/src/services/gsplcd.rs @@ -1,9 +1,12 @@ -//TODO: Verify if anonymous enum is properly represented +/* automatically generated by rust-bindgen */ -use ::Result; - -#[derive(Clone, Copy)] -#[repr(C)] +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] pub enum Enum_Unnamed1 { GSPLCD_SCREEN_TOP = 1, GSPLCD_SCREEN_BOTTOM = 2, @@ -12,6 +15,8 @@ pub enum Enum_Unnamed1 { extern "C" { pub fn gspLcdInit() -> Result; pub fn gspLcdExit(); - pub fn GSPLCD_PowerOnBacklight(screen: u32) -> Result; - pub fn GSPLCD_PowerOffBacklight(screen: u32) -> Result; + pub fn GSPLCD_PowerOnBacklight(screen: u32_) -> Result; + pub fn GSPLCD_PowerOffBacklight(screen: u32_) -> Result; + pub fn GSPLCD_GetVendors(vendors: *mut u8_) -> Result; } +use ::types::*; diff --git a/ctru-sys/src/services/hb.rs b/ctru-sys/src/services/hb.rs deleted file mode 100644 index 6d6264e..0000000 --- a/ctru-sys/src/services/hb.rs +++ /dev/null @@ -1,13 +0,0 @@ -use ::Result; -use ::libc::c_void; - - -extern "C" { - pub fn hbInit() -> Result; - pub fn hbExit() -> (); - pub fn HB_FlushInvalidateCache() -> Result; - pub fn HB_GetBootloaderAddresses(load3dsx: *mut *mut c_void, setArgv: *mut *mut c_void) - -> Result; - pub fn HB_ReprotectMemory(addr: *mut u32, pages: u32, mode: u32, reprotectedPages: *mut u32) - -> Result; -} diff --git a/ctru-sys/src/services/hid.rs b/ctru-sys/src/services/hid.rs index 8e3a025..2f7f95c 100644 --- a/ctru-sys/src/services/hid.rs +++ b/ctru-sys/src/services/hid.rs @@ -1,9 +1,12 @@ -use ::types::*; -use ::{Result, Handle}; - -pub const HID_SHAREDMEM_DEFAULT: u32 = 0x10000000; +/* automatically generated by rust-bindgen */ -#[repr(C)] +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] pub enum PAD_KEY { KEY_A = 1, KEY_B = 2, @@ -27,50 +30,57 @@ pub enum PAD_KEY { KEY_CPAD_RIGHT = 268435456, KEY_CPAD_LEFT = 536870912, KEY_CPAD_UP = 1073741824, - KEY_CPAD_DOWN = -2147483648, + KEY_CPAD_DOWN = 2147483648, KEY_UP = 1073741888, - KEY_DOWN = -2147483520, + KEY_DOWN = 2147483776, KEY_LEFT = 536870944, KEY_RIGHT = 268435472, - - // Generic catch-all directions - /*KEY_UP = KEY_DUP | KEY_CPAD_UP, - KEY_DOWN = KEY_DDOWN | KEY_CPAD_DOWN, - KEY_LEFT = KEY_DLEFT | KEY_CPAD_LEFT, - KEY_RIGHT = KEY_DRIGHT | KEY_CPAD_RIGHT,*/ } - #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Copy, Clone)] +#[derive(Debug)] pub struct touchPosition { - px: u16, - py: u16, + pub px: u16_, + pub py: u16_, +} +impl ::core::default::Default for touchPosition { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } } - #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Copy, Clone)] +#[derive(Debug)] pub struct circlePosition { - dx: s16, - dy: s16, + pub dx: s16, + pub dy: s16, +} +impl ::core::default::Default for circlePosition { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } } - #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Copy, Clone)] +#[derive(Debug)] pub struct accelVector { - x: s16, - y: s16, - z: s16 + pub x: s16, + pub y: s16, + pub z: s16, +} +impl ::core::default::Default for accelVector { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } } - #[repr(C)] -#[derive(Clone, Copy)] +#[derive(Copy, Clone)] +#[derive(Debug)] pub struct angularRate { - x: s16, //roll - z: s16, //yaw - y: s16, //pitch + pub x: s16, + pub z: s16, + pub y: s16, } - -#[repr(C)] +impl ::core::default::Default for angularRate { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] pub enum HID_Event { HIDEVENT_PAD0 = 0, HIDEVENT_PAD1 = 1, @@ -78,17 +88,18 @@ pub enum HID_Event { HIDEVENT_Gyro = 3, HIDEVENT_DebugPad = 4, HIDEVENT_MAX = 5, - } - - +extern "C" { + pub static mut hidMemHandle: Handle; + pub static mut hidSharedMem: *mut vu32; +} extern "C" { pub fn hidInit() -> Result; pub fn hidExit(); pub fn hidScanInput(); - pub fn hidKeysHeld() -> u32; - pub fn hidKeysDown() -> u32; - pub fn hidKeysUp() -> u32; + pub fn hidKeysHeld() -> u32_; + pub fn hidKeysDown() -> u32_; + pub fn hidKeysUp() -> u32_; pub fn hidTouchRead(pos: *mut touchPosition); pub fn hidCircleRead(pos: *mut circlePosition); pub fn hidAccelRead(vector: *mut accelVector); @@ -102,9 +113,7 @@ extern "C" { pub fn HIDUSER_DisableAccelerometer() -> Result; pub fn HIDUSER_EnableGyroscope() -> Result; pub fn HIDUSER_DisableGyroscope() -> Result; - pub fn HIDUSER_GetGyroscopeRawToDpsCoefficient(coeff: - *mut f32) - -> Result; - pub fn HIDUSER_GetSoundVolume(volume: *mut u8) -> Result; + pub fn HIDUSER_GetGyroscopeRawToDpsCoefficient(coeff: *mut f32) -> Result; + pub fn HIDUSER_GetSoundVolume(volume: *mut u8_) -> Result; } - +use ::types::*; diff --git a/ctru-sys/src/services/httpc.rs b/ctru-sys/src/services/httpc.rs index ba4eba4..9505f53 100644 --- a/ctru-sys/src/services/httpc.rs +++ b/ctru-sys/src/services/httpc.rs @@ -1,79 +1,126 @@ -use ::{Handle, Result}; +/* automatically generated by rust-bindgen */ +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] #[repr(C)] -#[derive(Copy)] +#[derive(Copy, Clone)] +#[derive(Debug)] pub struct httpcContext { pub servhandle: Handle, - pub httphandle: u32, -} -impl ::core::clone::Clone for httpcContext { - fn clone(&self) -> Self { *self } + pub httphandle: u32_, } impl ::core::default::Default for httpcContext { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } - -#[derive(Clone, Copy)] -#[repr(C)] +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum HTTPC_RequestMethod { + HTTPC_METHOD_GET = 1, + HTTPC_METHOD_POST = 2, + HTTPC_METHOD_HEAD = 3, + HTTPC_METHOD_PUT = 4, + HTTPC_METHOD_DELETE = 5, +} +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] pub enum HTTPC_RequestStatus { HTTPC_STATUS_REQUEST_IN_PROGRESS = 5, HTTPC_STATUS_DOWNLOAD_READY = 7, } - +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum HTTPC_KeepAlive { + HTTPC_KEEPALIVE_DISABLED = 0, + HTTPC_KEEPALIVE_ENABLED = 1, +} extern "C" { - pub fn httpcInit() -> Result; + pub fn httpcInit(sharedmem_size: u32_) -> Result; pub fn httpcExit(); pub fn httpcOpenContext(context: *mut httpcContext, - url: *mut u8, - use_defaultproxy: u32) -> Result; + method: HTTPC_RequestMethod, + url: *const ::libc::c_char, + use_defaultproxy: u32_) -> Result; pub fn httpcCloseContext(context: *mut httpcContext) -> Result; + pub fn httpcCancelConnection(context: *mut httpcContext) -> Result; pub fn httpcAddRequestHeaderField(context: *mut httpcContext, - name: *mut u8, - value: *mut u8) - -> Result; + name: *const ::libc::c_char, + value: *const ::libc::c_char) -> Result; + pub fn httpcAddPostDataAscii(context: *mut httpcContext, + name: *const ::libc::c_char, + value: *const ::libc::c_char) -> Result; + pub fn httpcAddPostDataRaw(context: *mut httpcContext, data: *const u32_, + len: u32_) -> Result; pub fn httpcBeginRequest(context: *mut httpcContext) -> Result; - pub fn httpcReceiveData(context: *mut httpcContext, buffer: *mut u8, - size: u32) -> Result; + pub fn httpcReceiveData(context: *mut httpcContext, buffer: *mut u8_, + size: u32_) -> Result; + pub fn httpcReceiveDataTimeout(context: *mut httpcContext, + buffer: *mut u8_, size: u32_, + timeout: u64_) -> Result; pub fn httpcGetRequestState(context: *mut httpcContext, out: *mut HTTPC_RequestStatus) -> Result; pub fn httpcGetDownloadSizeState(context: *mut httpcContext, - downloadedsize: *mut u32, - contentsize: *mut u32) -> Result; + downloadedsize: *mut u32_, + contentsize: *mut u32_) -> Result; pub fn httpcGetResponseStatusCode(context: *mut httpcContext, - out: *mut u32, delay: u64) -> Result; + out: *mut u32_) -> Result; + pub fn httpcGetResponseStatusCodeTimeout(context: *mut httpcContext, + out: *mut u32_, timeout: u64_) + -> Result; pub fn httpcGetResponseHeader(context: *mut httpcContext, - name: *mut u8, - value: *mut u8, - valuebuf_maxsize: u32) -> Result; - pub fn httpcDownloadData(context: *mut httpcContext, buffer: *mut u8, - size: u32, downloadedsize: *mut u32) -> Result; - pub fn HTTPC_Initialize(handle: Handle) -> Result; - pub fn HTTPC_InitializeConnectionSession(handle: Handle, - contextHandle: Handle) -> Result; - pub fn HTTPC_CreateContext(handle: Handle, - url: *mut u8, - contextHandle: *mut Handle) -> Result; - pub fn HTTPC_CloseContext(handle: Handle, contextHandle: Handle) + name: *const ::libc::c_char, + value: *mut ::libc::c_char, + valuebuf_maxsize: u32_) -> Result; + pub fn httpcAddTrustedRootCA(context: *mut httpcContext, cert: *const u8_, + certsize: u32_) -> Result; + pub fn httpcAddDefaultCert(context: *mut httpcContext, + certID: SSLC_DefaultRootCert) -> Result; + pub fn httpcSelectRootCertChain(context: *mut httpcContext, + RootCertChain_contexthandle: u32_) + -> Result; + pub fn httpcSetClientCert(context: *mut httpcContext, cert: *const u8_, + certsize: u32_, privk: *const u8_, + privk_size: u32_) -> Result; + pub fn httpcSetClientCertDefault(context: *mut httpcContext, + certID: SSLC_DefaultClientCert) + -> Result; + pub fn httpcSetClientCertContext(context: *mut httpcContext, + ClientCert_contexthandle: u32_) + -> Result; + pub fn httpcSetSSLOpt(context: *mut httpcContext, options: u32_) + -> Result; + pub fn httpcSetSSLClearOpt(context: *mut httpcContext, options: u32_) + -> Result; + pub fn httpcCreateRootCertChain(RootCertChain_contexthandle: *mut u32_) + -> Result; + pub fn httpcDestroyRootCertChain(RootCertChain_contexthandle: u32_) -> Result; - pub fn HTTPC_SetProxyDefault(handle: Handle, contextHandle: Handle) + pub fn httpcRootCertChainAddCert(RootCertChain_contexthandle: u32_, + cert: *const u8_, certsize: u32_, + cert_contexthandle: *mut u32_) -> Result; + pub fn httpcRootCertChainAddDefaultCert(RootCertChain_contexthandle: u32_, + certID: SSLC_DefaultRootCert, + cert_contexthandle: *mut u32_) -> Result; - pub fn HTTPC_AddRequestHeaderField(handle: Handle, contextHandle: Handle, - name: *mut u8, - value: *mut u8) + pub fn httpcRootCertChainRemoveCert(RootCertChain_contexthandle: u32_, + cert_contexthandle: u32_) -> Result; + pub fn httpcOpenClientCertContext(cert: *const u8_, certsize: u32_, + privk: *const u8_, privk_size: u32_, + ClientCert_contexthandle: *mut u32_) -> Result; - pub fn HTTPC_BeginRequest(handle: Handle, contextHandle: Handle) + pub fn httpcOpenDefaultClientCertContext(certID: SSLC_DefaultClientCert, + ClientCert_contexthandle: + *mut u32_) -> Result; + pub fn httpcCloseClientCertContext(ClientCert_contexthandle: u32_) -> Result; - pub fn HTTPC_ReceiveData(handle: Handle, contextHandle: Handle, - buffer: *mut u8, size: u32) -> Result; - pub fn HTTPC_GetRequestState(handle: Handle, contextHandle: Handle, - out: *mut HTTPC_RequestStatus) -> Result; - pub fn HTTPC_GetDownloadSizeState(handle: Handle, contextHandle: Handle, - downloadedsize: *mut u32, - contentsize: *mut u32) -> Result; - pub fn HTTPC_GetResponseHeader(handle: Handle, contextHandle: Handle, - name: *mut u8, - value: *mut u8, - valuebuf_maxsize: u32) -> Result; - pub fn HTTPC_GetResponseStatusCode(handle: Handle, contextHandle: Handle, - out: *mut u32) -> Result; + pub fn httpcDownloadData(context: *mut httpcContext, buffer: *mut u8_, + size: u32_, downloadedsize: *mut u32_) -> Result; + pub fn httpcSetKeepAlive(context: *mut httpcContext, + option: HTTPC_KeepAlive) -> Result; } +use ::types::*; +use super::sslc::*; diff --git a/ctru-sys/src/services/ir.rs b/ctru-sys/src/services/ir.rs index 94a626a..e94e93c 100644 --- a/ctru-sys/src/services/ir.rs +++ b/ctru-sys/src/services/ir.rs @@ -1,21 +1,25 @@ -use ::{Result, Handle}; +/* automatically generated by rust-bindgen */ +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] extern "C" { - pub fn iruInit(sharedmem_addr: *mut u32, sharedmem_size: u32) -> Result; + pub fn iruInit(sharedmem_addr: *mut u32_, sharedmem_size: u32_) -> Result; pub fn iruExit(); pub fn iruGetServHandle() -> Handle; - pub fn iruSendData(buf: *mut u8, size: u32, wait: u8) -> Result; - pub fn iruRecvData(buf: *mut u8, size: u32, flag: u8, - transfercount: *mut u32, wait: u8) -> Result; + pub fn iruSendData(buf: *mut u8_, size: u32_, wait: u8) -> Result; + pub fn iruRecvData(buf: *mut u8_, size: u32_, flag: u8_, + transfercount: *mut u32_, wait: u8) -> Result; pub fn IRU_Initialize() -> Result; pub fn IRU_Shutdown() -> Result; - pub fn IRU_StartSendTransfer(buf: *mut u8, size: u32) -> Result; + pub fn IRU_StartSendTransfer(buf: *mut u8_, size: u32_) -> Result; pub fn IRU_WaitSendTransfer() -> Result; - pub fn IRU_StartRecvTransfer(size: u32, flag: u8) -> Result; - pub fn IRU_WaitRecvTransfer(transfercount: *mut u32) -> Result; - pub fn IRU_SetBitRate(value: u8) -> Result; - pub fn IRU_GetBitRate(out: *mut u8) -> Result; - pub fn IRU_SetIRLEDState(value: u32) -> Result; - pub fn IRU_GetIRLEDRecvState(out: *mut u32) -> Result; + pub fn IRU_StartRecvTransfer(size: u32_, flag: u8_) -> Result; + pub fn IRU_WaitRecvTransfer(transfercount: *mut u32_) -> Result; + pub fn IRU_SetBitRate(value: u8_) -> Result; + pub fn IRU_GetBitRate(out: *mut u8_) -> Result; + pub fn IRU_SetIRLEDState(value: u32_) -> Result; + pub fn IRU_GetIRLEDRecvState(out: *mut u32_) -> Result; } - +use ::types::*; diff --git a/ctru-sys/src/services/irrst.rs b/ctru-sys/src/services/irrst.rs index 2f4c6eb..0ccf43e 100644 --- a/ctru-sys/src/services/irrst.rs +++ b/ctru-sys/src/services/irrst.rs @@ -1,21 +1,24 @@ -use ::{Result, Handle}; -use ::types::*; - -use super::hid::circlePosition; +/* automatically generated by rust-bindgen */ +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] extern "C" { pub static mut irrstMemHandle: Handle; pub static mut irrstSharedMem: *mut vu32; - +} +extern "C" { pub fn irrstInit() -> Result; pub fn irrstExit(); pub fn irrstScanInput(); - pub fn irrstKeysHeld() -> u32; + pub fn irrstKeysHeld() -> u32_; pub fn irrstCstickRead(pos: *mut circlePosition); pub fn irrstWaitForEvent(nextEvent: u8); pub fn IRRST_GetHandles(outMemHandle: *mut Handle, outEventHandle: *mut Handle) -> Result; - pub fn IRRST_Initialize(unk1: u32, unk2: u8) -> Result; + pub fn IRRST_Initialize(unk1: u32_, unk2: u8_) -> Result; pub fn IRRST_Shutdown() -> Result; - } +use ::types::*; +use super::hid::*; diff --git a/ctru-sys/src/services/mic.rs b/ctru-sys/src/services/mic.rs index 1037698..efc291f 100644 --- a/ctru-sys/src/services/mic.rs +++ b/ctru-sys/src/services/mic.rs @@ -1,42 +1,47 @@ -use ::{Handle, Result}; +/* automatically generated by rust-bindgen */ -#[derive(Clone, Copy)] -#[repr(C)] +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] pub enum MICU_Encoding { MICU_ENCODING_PCM8 = 0, MICU_ENCODING_PCM16 = 1, MICU_ENCODING_PCM8_SIGNED = 2, MICU_ENCODING_PCM16_SIGNED = 3, } - -#[derive(Clone, Copy)] -#[repr(C)] +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] pub enum MICU_SampleRate { MICU_SAMPLE_RATE_32730 = 0, MICU_SAMPLE_RATE_16360 = 1, MICU_SAMPLE_RATE_10910 = 2, MICU_SAMPLE_RATE_8180 = 3, } - extern "C" { - pub fn micInit(buffer: *mut u8, bufferSize: u32) -> Result; + pub fn micInit(buffer: *mut u8_, bufferSize: u32_) -> Result; pub fn micExit(); - pub fn micGetSampleDataSize() -> u32; - pub fn micGetLastSampleOffset() -> u32; - pub fn MICU_MapSharedMem(size: u32, handle: Handle) -> Result; + pub fn micGetSampleDataSize() -> u32_; + pub fn micGetLastSampleOffset() -> u32_; + pub fn MICU_MapSharedMem(size: u32_, handle: Handle) -> Result; pub fn MICU_UnmapSharedMem() -> Result; pub fn MICU_StartSampling(encoding: MICU_Encoding, - sampleRate: MICU_SampleRate, offset: u32, - size: u32, _loop: u8) -> Result; + sampleRate: MICU_SampleRate, offset: u32_, + size: u32_, loop_: u8) -> Result; pub fn MICU_AdjustSampling(sampleRate: MICU_SampleRate) -> Result; pub fn MICU_StopSampling() -> Result; pub fn MICU_IsSampling(sampling: *mut u8) -> Result; pub fn MICU_GetEventHandle(handle: *mut Handle) -> Result; - pub fn MICU_SetGain(gain: u8) -> Result; - pub fn MICU_GetGain(gain: *mut u8) -> Result; + pub fn MICU_SetGain(gain: u8_) -> Result; + pub fn MICU_GetGain(gain: *mut u8_) -> Result; pub fn MICU_SetPower(power: u8) -> Result; pub fn MICU_GetPower(power: *mut u8) -> Result; pub fn MICU_SetClamp(clamp: u8) -> Result; pub fn MICU_GetClamp(clamp: *mut u8) -> Result; pub fn MICU_SetAllowShellClosed(allowShellClosed: u8) -> Result; } +use ::types::*; diff --git a/ctru-sys/src/services/mod.rs b/ctru-sys/src/services/mod.rs index 76b7c35..880b32d 100644 --- a/ctru-sys/src/services/mod.rs +++ b/ctru-sys/src/services/mod.rs @@ -1,5 +1,6 @@ pub mod ac; pub mod am; +pub mod ampxi; pub mod apt; pub mod cam; pub mod cfgnor; @@ -8,20 +9,23 @@ pub mod dsp; pub mod fs; pub mod gspgpu; pub mod gsplcd; -pub mod hb; pub mod hid; pub mod httpc; pub mod ir; pub mod irrst; pub mod mic; pub mod mvd; +pub mod ndm; pub mod news; +pub mod nfc; pub mod ns; pub mod pm; pub mod ps; pub mod ptmsysm; pub mod ptmu; +pub mod pxidev; pub mod qtm; -pub mod soc; pub mod srvpm; +pub mod sslc; +pub mod uds; pub mod y2r; diff --git a/ctru-sys/src/services/mvd.rs b/ctru-sys/src/services/mvd.rs index fe8691c..e69de29 100644 --- a/ctru-sys/src/services/mvd.rs +++ b/ctru-sys/src/services/mvd.rs @@ -1,67 +0,0 @@ -use ::Result; - -#[derive(Clone, Copy)] -#[repr(C)] -pub enum MVDSTD_Mode { - MVDMODE_COLORFORMATCONV = 0, - MVDMODE_VIDEOPROCESSING = 1, -} - -#[derive(Clone, Copy)] -#[repr(C)] -pub enum MVDSTD_InputFormat { - MVD_INPUT_YUYV422 = 65537, - MVD_INPUT_H264 = 131073, -} - -#[derive(Clone, Copy)] -#[repr(C)] -pub enum MVDSTD_OutputFormat { MVD_OUTPUT_RGB565 = 262146, } - -#[repr(C)] -#[derive(Copy)] -pub struct MVDSTD_Config { - pub input_type: MVDSTD_InputFormat, - pub unk_x04: u32, - pub unk_x08: u32, - pub inwidth: u32, - pub inheight: u32, - pub physaddr_colorconv_indata: u32, - pub unk_x18: [u32; 10usize], - pub flag_x40: u32, - pub unk_x44: u32, - pub unk_x48: u32, - pub outheight0: u32, - pub outwidth0: u32, - pub unk_x54: u32, - pub output_type: MVDSTD_OutputFormat, - pub outwidth1: u32, - pub outheight1: u32, - pub physaddr_outdata0: u32, - pub physaddr_outdata1_colorconv: u32, - pub unk_x6c: [u32; 44usize], -} -impl ::core::clone::Clone for MVDSTD_Config { - fn clone(&self) -> Self { *self } -} -impl ::core::default::Default for MVDSTD_Config { - fn default() -> Self { unsafe { ::core::mem::zeroed() } } -} - -extern "C" { - pub fn mvdstdInit(mode: MVDSTD_Mode, input_type: MVDSTD_InputFormat, - output_type: MVDSTD_OutputFormat, size: u32) -> Result; - pub fn mvdstdExit(); - pub fn mvdstdGenerateDefaultConfig(config: *mut MVDSTD_Config, - input_width: u32, input_height: u32, - output_width: u32, - output_height: u32, - vaddr_colorconv_indata: *mut u32, - vaddr_outdata0: *mut u32, - vaddr_outdata1_colorconv: *mut u32); - pub fn mvdstdProcessFrame(config: *mut MVDSTD_Config, - h264_vaddr_inframe: *mut u32, - h264_inframesize: u32, h264_frameid: u32) - -> Result; - pub fn MVDSTD_SetConfig(config: *mut MVDSTD_Config) -> Result; -} diff --git a/ctru-sys/src/services/ndm.rs b/ctru-sys/src/services/ndm.rs new file mode 100644 index 0000000..be820ca --- /dev/null +++ b/ctru-sys/src/services/ndm.rs @@ -0,0 +1,23 @@ +/* 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 NDM_ExclusiveState { + EXCLUSIVE_STATE_NONE = 0, + EXCLUSIVE_STATE_INFRASTRUCTURE = 1, + EXCLUSIVE_STATE_LOCAL_COMMUNICATIONS = 2, + EXCLUSIVE_STATE_STREETPASS = 3, + EXCLUSIVE_STATE_STREETPASS_DATA = 4, +} +extern "C" { + pub fn ndmuInit() -> Result; + pub fn ndmuExit(); + pub fn ndmuEnterExclusiveState(state: NDM_ExclusiveState) -> Result; + pub fn ndmuLeaveExclusiveState() -> Result; +} +use ::types::*; diff --git a/ctru-sys/src/services/news.rs b/ctru-sys/src/services/news.rs index fb34f41..91a1414 100644 --- a/ctru-sys/src/services/news.rs +++ b/ctru-sys/src/services/news.rs @@ -1,11 +1,52 @@ -use ::Result; -use ::libc::c_void; +/* 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 NotificationHeader { + pub dataSet: u8, + pub unread: u8, + pub enableJPEG: u8, + pub isSpotPass: u8, + pub isOptedOut: u8, + pub unkData: [u8_; 3usize], + pub processID: u64_, + pub unkData2: [u8_; 8usize], + pub jumpParam: u64_, + pub unkData3: [u8_; 8usize], + pub time: u64_, + pub title: [u16_; 32usize], +} +impl ::core::default::Default for NotificationHeader { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} extern "C" { pub fn newsInit() -> Result; pub fn newsExit(); - pub fn NEWS_AddNotification(title: *const u16, titleLength: u32, - message: *const u16, messageLength: u32, - imageData: *const c_void, - imageSize: u32, jpeg: u8) -> Result; + pub fn NEWS_AddNotification(title: *const u16_, titleLength: u32_, + message: *const u16_, messageLength: u32_, + imageData: *const ::libc::c_void, + imageSize: u32_, jpeg: u8) -> Result; + pub fn NEWS_GetTotalNotifications(num: *mut u32_) -> Result; + pub fn NEWS_SetNotificationHeader(news_id: u32_, + header: *const NotificationHeader) + -> Result; + pub fn NEWS_GetNotificationHeader(news_id: u32_, + header: *mut NotificationHeader) + -> Result; + pub fn NEWS_SetNotificationMessage(news_id: u32_, message: *const u16_, + size: u32_) -> Result; + pub fn NEWS_GetNotificationMessage(news_id: u32_, message: *mut u16_, + size: *mut u32_) -> Result; + pub fn NEWS_SetNotificationImage(news_id: u32_, + buffer: *const ::libc::c_void, + size: u32_) -> Result; + pub fn NEWS_GetNotificationImage(news_id: u32_, + buffer: *mut ::libc::c_void, + size: *mut u32_) -> Result; } +use ::types::*; diff --git a/ctru-sys/src/services/nfc.rs b/ctru-sys/src/services/nfc.rs new file mode 100644 index 0000000..c6ac09e --- /dev/null +++ b/ctru-sys/src/services/nfc.rs @@ -0,0 +1,127 @@ +/* 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 NFC_OpType { NFC_OpType_1 = 1, NFC_OpType_NFCTag = 2, } +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum NFC_TagState { + NFC_TagState_Uninitialized = 0, + NFC_TagState_ScanningStopped = 1, + NFC_TagState_Scanning = 2, + NFC_TagState_InRange = 3, + NFC_TagState_OutOfRange = 4, + NFC_TagState_DataReady = 5, +} +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum Enum_Unnamed1 { + NFC_amiiboFlag_Setup = 16, + NFC_amiiboFlag_AppDataSetup = 32, +} +#[repr(C)] +#[derive(Copy)] +pub struct NFC_TagInfo { + pub id_offset_size: u16_, + pub unk_x2: u8_, + pub unk_x3: u8_, + pub id: [u8_; 40usize], +} +impl ::core::clone::Clone for NFC_TagInfo { + fn clone(&self) -> Self { *self } +} +impl ::core::default::Default for NFC_TagInfo { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy)] +pub struct NFC_AmiiboSettings { + pub mii: [u8_; 96usize], + pub nickname: [u16_; 11usize], + pub flags: u8_, + pub countrycodeid: u8_, + pub setupdate_year: u16_, + pub setupdate_month: u8_, + pub setupdate_day: u8_, + pub unk_x7c: [u8_; 44usize], +} +impl ::core::clone::Clone for NFC_AmiiboSettings { + fn clone(&self) -> Self { *self } +} +impl ::core::default::Default for NFC_AmiiboSettings { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy)] +pub struct NFC_AmiiboConfig { + pub lastwritedate_year: u16_, + pub lastwritedate_month: u8_, + pub lastwritedate_day: u8_, + pub write_counter: u16_, + pub val_x6: u16_, + pub val_x8: u8_, + pub val_x9: u8_, + pub val_xa: u16_, + pub val_xc: u8_, + pub pagex4_byte3: u8_, + pub appdata_size: u8_, + pub zeros: [u8_; 49usize], +} +impl ::core::clone::Clone for NFC_AmiiboConfig { + fn clone(&self) -> Self { *self } +} +impl ::core::default::Default for NFC_AmiiboConfig { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy)] +pub struct NFC_AppDataInitStruct { + pub data_x0: [u8_; 12usize], + pub data_xc: [u8_; 48usize], +} +impl ::core::clone::Clone for NFC_AppDataInitStruct { + fn clone(&self) -> Self { *self } +} +impl ::core::default::Default for NFC_AppDataInitStruct { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct NFC_AppDataWriteStruct { + pub id: [u8_; 10usize], + pub id_size: u8_, + pub unused_xb: [u8_; 21usize], +} +impl ::core::default::Default for NFC_AppDataWriteStruct { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +extern "C" { + pub fn nfcInit(type_: NFC_OpType) -> Result; + pub fn nfcExit(); + pub fn nfcGetSessionHandle() -> Handle; + pub fn nfcStartScanning(inval: u16_) -> Result; + pub fn nfcStopScanning(); + pub fn nfcLoadAmiiboData() -> Result; + pub fn nfcResetTagScanState() -> Result; + pub fn nfcUpdateStoredAmiiboData() -> Result; + pub fn nfcGetTagState(state: *mut NFC_TagState) -> Result; + 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: ::libc::size_t) + -> Result; + 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; +} +use ::types::*; diff --git a/ctru-sys/src/services/ns.rs b/ctru-sys/src/services/ns.rs index c48e176..67f6d63 100644 --- a/ctru-sys/src/services/ns.rs +++ b/ctru-sys/src/services/ns.rs @@ -1,9 +1,17 @@ -use ::Result; +/* automatically generated by rust-bindgen */ +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] extern "C" { pub fn nsInit() -> Result; pub fn nsExit(); - pub fn NS_LaunchTitle(titleid: u64, launch_flags: u32, procid: *mut u32) -> Result; - pub fn NS_RebootToTitle(mediatype: u8, titleid: u64) -> Result; + pub fn NS_LaunchFIRM(titleid: u64_) -> Result; + pub fn NS_LaunchTitle(titleid: u64_, launch_flags: u32_, + procid: *mut u32_) -> Result; + pub fn NS_LaunchApplicationFIRM(titleid: u64_, flags: u32_) -> Result; + pub fn NS_RebootToTitle(mediatype: u8_, titleid: u64_) -> Result; + pub fn NS_TerminateProcessTID(titleid: u64_) -> Result; } - +use ::types::*; diff --git a/ctru-sys/src/services/pm.rs b/ctru-sys/src/services/pm.rs index 958dbc4..34896a9 100644 --- a/ctru-sys/src/services/pm.rs +++ b/ctru-sys/src/services/pm.rs @@ -1,24 +1,19 @@ -use ::{Handle, Result}; -use ::libc::c_void; +/* automatically generated by rust-bindgen */ +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] extern "C" { pub fn pmInit() -> Result; pub fn pmExit(); - pub fn PM_LaunchTitle(mediatype: u8, titleid: u64, launch_flags: u32) + pub fn PM_LaunchTitle(mediatype: u8_, titleid: u64_, launch_flags: u32_) -> Result; - pub fn PM_GetTitleExheaderFlags(mediatype: u8, titleid: u64, - out: *mut u8) -> Result; - pub fn PM_SetFIRMLaunchParams(size: u32, _in: *mut u8) -> Result; - pub fn PM_GetFIRMLaunchParams(size: u32, out: *mut u8) -> Result; - pub fn PM_LaunchFIRMSetParams(firm_titleid_low: u32, size: u32, - _in: *mut u8) -> Result; - pub fn srvPmInit() -> Result; - pub fn srvPmExit(); - pub fn SRVPM_PublishToProcess(notificationId: u32, process: Handle) - -> Result; - pub fn SRVPM_PublishToAll(notificationId: u32) -> Result; - pub fn SRVPM_RegisterProcess(procid: u32, count: u32, - serviceaccesscontrol: c_void) -> Result; - pub fn SRVPM_UnregisterProcess(procid: u32) -> Result; + pub fn PM_GetTitleExheaderFlags(mediatype: u8_, titleid: u64_, + out: *mut u8_) -> Result; + pub fn PM_SetFIRMLaunchParams(size: u32_, in_: *mut u8_) -> Result; + pub fn PM_GetFIRMLaunchParams(size: u32_, out: *mut u8_) -> Result; + pub fn PM_LaunchFIRMSetParams(firm_titleid_low: u32_, size: u32_, + in_: *mut u8_) -> Result; } - +use ::types::*; diff --git a/ctru-sys/src/services/pmtsym.rs b/ctru-sys/src/services/pmtsym.rs new file mode 100644 index 0000000..0684f65 --- /dev/null +++ b/ctru-sys/src/services/pmtsym.rs @@ -0,0 +1,8 @@ +/* automatically generated by rust-bindgen */ + +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] + +use ::types::*; diff --git a/ctru-sys/src/services/ps.rs b/ctru-sys/src/services/ps.rs index e59a08d..3a1e16c 100644 --- a/ctru-sys/src/services/ps.rs +++ b/ctru-sys/src/services/ps.rs @@ -1,7 +1,12 @@ -use ::Result; +/* automatically generated by rust-bindgen */ -#[derive(Clone, Copy)] -#[repr(C)] +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] pub enum PS_AESAlgorithm { PS_ALGORITHM_CBC_ENC = 0, PS_ALGORITHM_CBC_DEC = 1, @@ -10,9 +15,9 @@ pub enum PS_AESAlgorithm { PS_ALGORITHM_CCM_ENC = 4, PS_ALGORITHM_CCM_DEC = 5, } - -#[derive(Clone, Copy)] -#[repr(C)] +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] pub enum PS_AESKeyType { PS_KEYSLOT_0D = 0, PS_KEYSLOT_2D = 1, @@ -25,22 +30,24 @@ pub enum PS_AESKeyType { PS_KEYSLOT_36 = 8, PS_KEYSLOT_39_NFC = 9, } - extern "C" { pub fn psInit() -> Result; pub fn psExit(); - pub fn PS_EncryptDecryptAes(size: u32, _in: *mut u8, out: *mut u8, + pub fn PS_EncryptDecryptAes(size: u32_, in_: *mut u8_, out: *mut u8_, aes_algo: PS_AESAlgorithm, - key_type: PS_AESKeyType, iv: *mut u8) + key_type: PS_AESKeyType, iv: *mut u8_) -> Result; - pub fn PS_EncryptSignDecryptVerifyAesCcm(_in: *mut u8, in_size: u32, - out: *mut u8, out_size: u32, - data_len: u32, - mac_data_len: u32, - mac_len: u32, + pub fn PS_EncryptSignDecryptVerifyAesCcm(in_: *mut u8_, in_size: u32_, + out: *mut u8_, out_size: u32_, + data_len: u32_, + mac_data_len: u32_, + mac_len: u32_, aes_algo: PS_AESAlgorithm, key_type: PS_AESKeyType, - nonce: *mut u8) -> Result; - pub fn PS_GetLocalFriendCodeSeed(seed: *mut u64) -> Result; - pub fn PS_GetDeviceId(device_id: *mut u32) -> Result; + 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: ::libc::size_t) + -> Result; } +use ::types::*; diff --git a/ctru-sys/src/services/ptmsym.rs b/ctru-sys/src/services/ptmsym.rs new file mode 100644 index 0000000..f536294 --- /dev/null +++ b/ctru-sys/src/services/ptmsym.rs @@ -0,0 +1,15 @@ +/* automatically generated by rust-bindgen */ + +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] +extern "C" { + pub fn ptmSysmInit() -> Result; + pub fn ptmSysmExit(); + pub fn PTMSYSM_CheckNew3DS() -> Result; + pub fn PTMSYSM_ConfigureNew3DSCPU(value: u8_) -> Result; + pub fn PTMSYSM_ShutdownAsync(timeout: u64_) -> Result; + pub fn PTMSYSM_RebootAsync(timeout: u64_) -> Result; +} +use ::types::*; diff --git a/ctru-sys/src/services/ptmsysm.rs b/ctru-sys/src/services/ptmsysm.rs index 7507fd5..f536294 100644 --- a/ctru-sys/src/services/ptmsysm.rs +++ b/ctru-sys/src/services/ptmsysm.rs @@ -1,7 +1,15 @@ -use ::Result; +/* automatically generated by rust-bindgen */ +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] extern "C" { pub fn ptmSysmInit() -> Result; pub fn ptmSysmExit(); - pub fn PTMSYSM_ConfigureNew3DSCPU(value: u8) -> Result; + pub fn PTMSYSM_CheckNew3DS() -> Result; + pub fn PTMSYSM_ConfigureNew3DSCPU(value: u8_) -> Result; + pub fn PTMSYSM_ShutdownAsync(timeout: u64_) -> Result; + pub fn PTMSYSM_RebootAsync(timeout: u64_) -> Result; } +use ::types::*; diff --git a/ctru-sys/src/services/ptmu.rs b/ctru-sys/src/services/ptmu.rs index e230a37..ab8ab82 100644 --- a/ctru-sys/src/services/ptmu.rs +++ b/ctru-sys/src/services/ptmu.rs @@ -1,11 +1,16 @@ -use ::Result; +/* automatically generated by rust-bindgen */ +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] extern "C" { pub fn ptmuInit() -> Result; pub fn ptmuExit(); - pub fn PTMU_GetShellState(out: *mut u8) -> Result; - pub fn PTMU_GetBatteryLevel(out: *mut u8) -> Result; - pub fn PTMU_GetBatteryChargeState(out: *mut u8) -> Result; - pub fn PTMU_GetPedometerState(out: *mut u8) -> Result; - pub fn PTMU_GetTotalStepCount(steps: *mut u32) -> Result; + pub fn PTMU_GetShellState(out: *mut u8_) -> Result; + pub fn PTMU_GetBatteryLevel(out: *mut u8_) -> Result; + pub fn PTMU_GetBatteryChargeState(out: *mut u8_) -> Result; + pub fn PTMU_GetPedometerState(out: *mut u8_) -> Result; + pub fn PTMU_GetTotalStepCount(steps: *mut u32_) -> Result; } +use ::types::*; diff --git a/ctru-sys/src/services/pxidev.rs b/ctru-sys/src/services/pxidev.rs new file mode 100644 index 0000000..c5cf290 --- /dev/null +++ b/ctru-sys/src/services/pxidev.rs @@ -0,0 +1,50 @@ +/* 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 PXIDEV_WaitType { + WAIT_NONE = 0, + WAIT_SLEEP = 1, + WAIT_IREQ_RETURN = 2, + WAIT_IREQ_CONTINUE = 3, +} +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum PXIDEV_DeassertType { + DEASSERT_NONE = 0, + DEASSERT_BEFORE_WAIT = 1, + DEASSERT_AFTER_WAIT = 2, +} +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct PXIDEV_SPIBuffer { + pub ptr: *mut ::libc::c_void, + pub size: u32_, + pub transferOption: u8_, + pub waitOperation: u64_, +} +impl ::core::default::Default for PXIDEV_SPIBuffer { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +extern "C" { + pub fn pxiDevInit() -> Result; + pub fn pxiDevExit(); + pub fn PXIDEV_SPIMultiWriteRead(header: *mut PXIDEV_SPIBuffer, + writeBuffer1: *mut PXIDEV_SPIBuffer, + readBuffer1: *mut PXIDEV_SPIBuffer, + writeBuffer2: *mut PXIDEV_SPIBuffer, + readBuffer2: *mut PXIDEV_SPIBuffer, + footer: *mut PXIDEV_SPIBuffer) -> Result; + pub fn PXIDEV_SPIWriteRead(bytesRead: *mut u32_, + initialWaitOperation: u64_, + writeBuffer: *mut PXIDEV_SPIBuffer, + readBuffer: *mut PXIDEV_SPIBuffer) -> Result; +} +use ::types::*; diff --git a/ctru-sys/src/services/qtm.rs b/ctru-sys/src/services/qtm.rs index 30d7595..37bc8db 100644 --- a/ctru-sys/src/services/qtm.rs +++ b/ctru-sys/src/services/qtm.rs @@ -1,34 +1,32 @@ -use ::Result; +/* automatically generated by rust-bindgen */ +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] #[repr(C)] -#[derive(Copy)] +#[derive(Copy, Clone)] +#[derive(Debug)] pub struct QTM_HeadTrackingInfoCoord { pub x: f32, pub y: f32, } -impl ::core::clone::Clone for QTM_HeadTrackingInfoCoord { - fn clone(&self) -> Self { *self } -} impl ::core::default::Default for QTM_HeadTrackingInfoCoord { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } - #[repr(C)] -#[derive(Copy)] +#[derive(Copy, Clone)] +#[derive(Debug)] pub struct QTM_HeadTrackingInfo { - pub flags: [u8; 5usize], - pub padding: [u8; 3usize], + pub flags: [u8_; 5usize], + pub padding: [u8_; 3usize], pub floatdata_x08: f32, pub coords0: [QTM_HeadTrackingInfoCoord; 4usize], - pub unk_x2c: [u32; 5usize], -} -impl ::core::clone::Clone for QTM_HeadTrackingInfo { - fn clone(&self) -> Self { *self } + pub unk_x2c: [u32_; 5usize], } impl ::core::default::Default for QTM_HeadTrackingInfo { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } - extern "C" { pub fn qtmInit() -> Result; pub fn qtmExit(); @@ -36,9 +34,9 @@ extern "C" { pub fn qtmCheckHeadFullyDetected(info: *mut QTM_HeadTrackingInfo) -> u8; pub fn qtmConvertCoordToScreen(coord: *mut QTM_HeadTrackingInfoCoord, screen_width: *mut f32, - screen_height: - *mut f32, - x: *mut u32, y: *mut u32) -> Result; - pub fn QTM_GetHeadTrackingInfo(val: u64, out: *mut QTM_HeadTrackingInfo) + screen_height: *mut f32, x: *mut u32_, + y: *mut u32_) -> Result; + pub fn QTM_GetHeadTrackingInfo(val: u64_, out: *mut QTM_HeadTrackingInfo) -> Result; } +use ::types::*; diff --git a/ctru-sys/src/services/soc.rs b/ctru-sys/src/services/soc.rs index 3a1e2ec..94ac632 100644 --- a/ctru-sys/src/services/soc.rs +++ b/ctru-sys/src/services/soc.rs @@ -1,7 +1,108 @@ -use ::Result; +/* 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 NetworkOpt { + NETOPT_MAC_ADDRESS = 4100, + NETOPT_ARP_TABLE = 12290, + NETOPT_IP_INFO = 16387, + NETOPT_IP_MTU = 16388, + NETOPT_ROUTING_TABLE = 16390, + NETOPT_UDP_NUMBER = 32770, + NETOPT_UDP_TABLE = 32771, + NETOPT_TCP_NUMBER = 36866, + NETOPT_TCP_TABLE = 36867, + NETOPT_DNS_TABLE = 45059, + NETOPT_DHCP_LEASE_TIME = 49153, +} +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct SOCU_ARPTableEntry { + pub unk0: u32_, + pub ip: in_addr, + pub mac: [u8_; 6usize], + pub padding: [u8_; 2usize], +} +impl ::core::default::Default for SOCU_ARPTableEntry { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct SOCU_IPInfo { + pub ip: in_addr, + pub netmask: in_addr, + pub broadcast: in_addr, +} +impl ::core::default::Default for SOCU_IPInfo { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct SOCU_RoutingTableEntry { + pub dest_ip: in_addr, + pub netmask: in_addr, + pub gateway: in_addr, + pub flags: u32_, + pub time: u64_, +} +impl ::core::default::Default for SOCU_RoutingTableEntry { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct SOCU_UDPTableEntry { + pub local: sockaddr_storage, + pub remote: sockaddr_storage, +} +impl ::core::default::Default for SOCU_UDPTableEntry { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct SOCU_TCPTableEntry { + pub state: u32_, + pub local: sockaddr_storage, + pub remote: sockaddr_storage, +} +impl ::core::default::Default for SOCU_TCPTableEntry { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct SOCU_DNSTableEntry { + pub family: u32_, + pub ip: in_addr, + pub padding: [u8_; 12usize], +} +impl ::core::default::Default for SOCU_DNSTableEntry { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} extern "C" { - pub fn SOC_Init(context_addr: *mut u32, context_size: u32) -> Result; - pub fn SOC_Exit() -> Result; - pub fn gethostid() -> i32; + 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: ::libc::size_t) + -> ::libc::c_int; + pub fn SOCU_ShutdownSockets() -> ::libc::c_int; + pub fn SOCU_CloseSockets() -> ::libc::c_int; + pub fn SOCU_GetNetworkOpt(level: ::libc::c_int, optname: NetworkOpt, + optval: *mut ::libc::c_void, + optlen: *mut socklen_t) -> ::libc::c_int; + pub fn SOCU_GetIPInfo(ip: *mut in_addr, netmask: *mut in_addr, + broadcast: *mut in_addr) -> ::libc::c_int; + pub fn SOCU_AddGlobalSocket(sockfd: ::libc::c_int) -> ::libc::c_int; } +use ::types::*; +use sys::socket::*; +use sys::inaddr::*; diff --git a/ctru-sys/src/services/srvpm.rs b/ctru-sys/src/services/srvpm.rs index 47ae21f..f13e8db 100644 --- a/ctru-sys/src/services/srvpm.rs +++ b/ctru-sys/src/services/srvpm.rs @@ -1,12 +1,18 @@ -use ::{Handle, Result}; -use ::libc::c_void; +/* automatically generated by rust-bindgen */ +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] extern "C" { pub fn srvPmInit() -> Result; pub fn srvPmExit(); - pub fn SRVPM_PublishToProcess(notificationId: u32, process: Handle) -> Result; - pub fn SRVPM_PublishToAll(notificationId: u32) -> Result; - pub fn SRVPM_RegisterProcess(procid: u32, count: u32, - serviceaccesscontrol: c_void) -> Result; - pub fn SRVPM_UnregisterProcess(procid: u32) -> Result; + pub fn SRVPM_PublishToProcess(notificationId: u32_, process: Handle) + -> Result; + pub fn SRVPM_PublishToAll(notificationId: u32_) -> Result; + pub fn SRVPM_RegisterProcess(procid: u32_, count: u32_, + serviceaccesscontrol: *mut ::libc::c_void) + -> Result; + pub fn SRVPM_UnregisterProcess(procid: u32_) -> Result; } +use ::types::*; diff --git a/ctru-sys/src/services/sslc.rs b/ctru-sys/src/services/sslc.rs new file mode 100644 index 0000000..f310269 --- /dev/null +++ b/ctru-sys/src/services/sslc.rs @@ -0,0 +1,115 @@ +/* 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 sslcContext { + pub servhandle: Handle, + pub sslchandle: u32_, + pub sharedmem_handle: Handle, +} +impl ::core::default::Default for sslcContext { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum SSLC_DefaultRootCert { + SSLC_DefaultRootCert_Nintendo_CA = 1, + SSLC_DefaultRootCert_Nintendo_CA_G2 = 2, + SSLC_DefaultRootCert_Nintendo_CA_G3 = 3, + SSLC_DefaultRootCert_Nintendo_Class2_CA = 4, + SSLC_DefaultRootCert_Nintendo_Class2_CA_G2 = 5, + SSLC_DefaultRootCert_Nintendo_Class2_CA_G3 = 6, + SSLC_DefaultRootCert_CyberTrust = 7, + SSLC_DefaultRootCert_AddTrust_External_CA = 8, + SSLC_DefaultRootCert_COMODO = 9, + SSLC_DefaultRootCert_USERTrust = 10, + SSLC_DefaultRootCert_DigiCert_EV = 11, +} +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum SSLC_DefaultClientCert { SSLC_DefaultClientCert_ClCertA = 64, } +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum Enum_Unnamed1 { + SSLCOPT_Default = 0, + SSLCOPT_DisableVerify = 512, + SSLCOPT_TLSv10 = 2048, +} +extern "C" { + pub fn sslcInit(session_handle: Handle) -> Result; + pub fn sslcExit(); + pub fn sslcCreateRootCertChain(RootCertChain_contexthandle: *mut u32_) + -> Result; + pub fn sslcDestroyRootCertChain(RootCertChain_contexthandle: u32_) + -> Result; + pub fn sslcAddTrustedRootCA(RootCertChain_contexthandle: u32_, + cert: *const u8_, certsize: u32_, + cert_contexthandle: *mut u32_) -> Result; + pub fn sslcRootCertChainAddDefaultCert(RootCertChain_contexthandle: u32_, + certID: SSLC_DefaultRootCert, + cert_contexthandle: *mut u32_) + -> Result; + pub fn sslcRootCertChainRemoveCert(RootCertChain_contexthandle: u32_, + cert_contexthandle: u32_) -> Result; + pub fn sslcCreate8CertChain(CertChain_contexthandle: *mut u32_) -> Result; + pub fn sslcDestroy8CertChain(CertChain_contexthandle: u32_) -> Result; + pub fn sslc8CertChainAddCert(CertChain_contexthandle: u32_, + cert: *const u8_, certsize: u32_, + cert_contexthandle: *mut u32_) -> Result; + pub fn sslc8CertChainAddDefaultCert(CertChain_contexthandle: u32_, + certID: u8_, + cert_contexthandle: *mut u32_) + -> Result; + pub fn sslc8CertChainRemoveCert(CertChain_contexthandle: u32_, + cert_contexthandle: u32_) -> Result; + pub fn sslcOpenClientCertContext(cert: *const u8_, certsize: u32_, + key: *const u8_, keysize: u32_, + ClientCert_contexthandle: *mut u32_) + -> Result; + pub fn sslcOpenDefaultClientCertContext(certID: SSLC_DefaultClientCert, + ClientCert_contexthandle: + *mut u32_) -> Result; + pub fn sslcCloseClientCertContext(ClientCert_contexthandle: u32_) + -> Result; + pub fn sslcSeedRNG() -> Result; + pub fn sslcGenerateRandomData(buf: *mut u8_, size: u32_) -> Result; + pub fn sslcCreateContext(context: *mut sslcContext, sockfd: ::libc::c_int, + input_opt: u32_, hostname: *const ::libc::c_char) + -> Result; + pub fn sslcDestroyContext(context: *mut sslcContext) -> Result; + pub fn sslcStartConnection(context: *mut sslcContext, + internal_retval: *mut ::libc::c_int, + out: *mut u32_) -> Result; + pub fn sslcRead(context: *mut sslcContext, buf: *mut ::libc::c_void, + len: ::libc::size_t, peek: u8) -> Result; + pub fn sslcWrite(context: *mut sslcContext, buf: *const ::libc::c_void, + len: ::libc::size_t) -> Result; + pub fn sslcContextSetRootCertChain(context: *mut sslcContext, + handle: u32_) -> Result; + pub fn sslcContextSetClientCert(context: *mut sslcContext, handle: u32_) + -> Result; + pub fn sslcContextSetHandle8(context: *mut sslcContext, handle: u32_) + -> Result; + pub fn sslcContextClearOpt(context: *mut sslcContext, bitmask: u32_) + -> Result; + pub fn sslcContextGetProtocolCipher(context: *mut sslcContext, + outprotocols: *mut ::libc::c_char, + outprotocols_maxsize: u32_, + outcipher: *mut ::libc::c_char, + outcipher_maxsize: u32_) -> Result; + pub fn sslcContextGetState(context: *mut sslcContext, out: *mut u32_) + -> Result; + pub fn sslcContextInitSharedmem(context: *mut sslcContext, buf: *mut u8_, + size: u32_) -> Result; + pub fn sslcAddCert(context: *mut sslcContext, buf: *const u8_, size: u32_) + -> Result; +} +use ::types::*; diff --git a/ctru-sys/src/services/uds.rs b/ctru-sys/src/services/uds.rs new file mode 100644 index 0000000..bf49b90 --- /dev/null +++ b/ctru-sys/src/services/uds.rs @@ -0,0 +1,6 @@ +/* automatically generated by rust-bindgen */ + +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] diff --git a/ctru-sys/src/services/y2r.rs b/ctru-sys/src/services/y2r.rs index 6554ad6..96d7ac4 100644 --- a/ctru-sys/src/services/y2r.rs +++ b/ctru-sys/src/services/y2r.rs @@ -1,6 +1,5 @@ -use ::{Handle, Result}; -use ::libc::c_void; use ::types::*; +use ::libc::c_void; #[derive(Clone, Copy)] #[repr(C)] diff --git a/ctru-sys/src/svc.rs b/ctru-sys/src/svc.rs index 12efcca..fb41bc0 100644 --- a/ctru-sys/src/svc.rs +++ b/ctru-sys/src/svc.rs @@ -1,13 +1,13 @@ -//TODO: Implement static functions +/* automatically generated by rust-bindgen */ -use {Handle, Result}; -use libc::c_void; -use ThreadFunc; -use types::*; - -#[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 MemOp { MEMOP_FREE = 1, MEMOP_RESERVE = 2, MEMOP_ALLOC = 3, @@ -22,10 +22,10 @@ pub enum Enum_Unnamed1 { MEMOP_LINEAR_FLAG = 65536, MEMOP_ALLOC_LINEAR = 65539, } -pub type MemOp = Enum_Unnamed1; -#[derive(Clone, Copy)] -#[repr(C)] -pub enum Enum_Unnamed2 { +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum MemState { MEMSTATE_FREE = 0, MEMSTATE_RESERVED = 1, MEMSTATE_IO = 2, @@ -39,142 +39,128 @@ pub enum Enum_Unnamed2 { MEMSTATE_ALIASCODE = 10, MEMSTATE_LOCKED = 11, } -pub type MemState = Enum_Unnamed2; -#[derive(Clone, Copy)] -#[repr(C)] -pub enum Enum_Unnamed3 { +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum MemPerm { MEMPERM_READ = 1, MEMPERM_WRITE = 2, MEMPERM_EXECUTE = 4, MEMPERM_DONTCARE = 268435456, } -pub type MemPerm = Enum_Unnamed3; #[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed4 { - pub base_addr: u32, - pub size: u32, - pub perm: u32, - pub state: u32, -} -impl ::core::clone::Clone for Struct_Unnamed4 { - fn clone(&self) -> Self { *self } -} -impl ::core::default::Default for Struct_Unnamed4 { +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct MemInfo { + 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() } } } -pub type MemInfo = Struct_Unnamed4; #[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed5 { - pub flags: u32, +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct PageInfo { + pub flags: u32_, } -impl ::core::clone::Clone for Struct_Unnamed5 { - fn clone(&self) -> Self { *self } -} -impl ::core::default::Default for Struct_Unnamed5 { +impl ::core::default::Default for PageInfo { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } -pub type PageInfo = Struct_Unnamed5; -#[derive(Clone, Copy)] -#[repr(C)] -pub enum Enum_Unnamed6 { +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum ArbitrationType { ARBITRATION_SIGNAL = 0, ARBITRATION_WAIT_IF_LESS_THAN = 1, ARBITRATION_DECREMENT_AND_WAIT_IF_LESS_THAN = 2, ARBITRATION_WAIT_IF_LESS_THAN_TIMEOUT = 3, ARBITRATION_DECREMENT_AND_WAIT_IF_LESS_THAN_TIMEOUT = 4, } -pub type ArbitrationType = Enum_Unnamed6; -#[derive(Clone, Copy)] -#[repr(C)] -pub enum Enum_Unnamed7 { THREADINFO_TYPE_UNKNOWN = 0, } -pub type ThreadInfoType = Enum_Unnamed7; -#[derive(Clone, Copy)] +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum ResetType { RESET_ONESHOT = 0, RESET_STICKY = 1, RESET_PULSE = 2, } +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum ThreadInfoType { THREADINFO_TYPE_UNKNOWN = 0, } +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum ProcessEventReason { REASON_CREATE = 1, REASON_ATTACH = 2, } #[repr(C)] -pub enum Enum_Unnamed8 { REASON_CREATE = 1, REASON_ATTACH = 2, } -pub type ProcessEventReason = Enum_Unnamed8; -#[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed9 { - pub program_id: u64, - pub process_name: [u8; 8usize], - pub process_id: u32, - pub reason: u32, -} -impl ::core::clone::Clone for Struct_Unnamed9 { - fn clone(&self) -> Self { *self } -} -impl ::core::default::Default for Struct_Unnamed9 { +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct ProcessEvent { + 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() } } } -pub type ProcessEvent = Struct_Unnamed9; -#[derive(Clone, Copy)] -#[repr(C)] -pub enum Enum_Unnamed10 { +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum ExitProcessEventReason { EXITPROCESS_EVENT_NONE = 0, EXITPROCESS_EVENT_TERMINATE = 1, EXITPROCESS_EVENT_UNHANDLED_EXCEPTION = 2, } -pub type ExitProcessEventReason = Enum_Unnamed10; #[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed11 { - pub reason: u32, -} -impl ::core::clone::Clone for Struct_Unnamed11 { - fn clone(&self) -> Self { *self } +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct ExitProcessEvent { + pub reason: u32_, } -impl ::core::default::Default for Struct_Unnamed11 { +impl ::core::default::Default for ExitProcessEvent { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } -pub type ExitProcessEvent = Struct_Unnamed11; #[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed12 { - pub creator_thread_id: u32, - pub base_addr: u32, - pub entry_point: u32, -} -impl ::core::clone::Clone for Struct_Unnamed12 { - fn clone(&self) -> Self { *self } -} -impl ::core::default::Default for Struct_Unnamed12 { +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct CreateThreadEvent { + 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() } } } -pub type CreateThreadEvent = Struct_Unnamed12; -#[derive(Clone, Copy)] -#[repr(C)] -pub enum Enum_Unnamed13 { +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum ExitThreadEventReason { EXITTHREAD_EVENT_NONE = 0, EXITTHREAD_EVENT_TERMINATE = 1, EXITTHREAD_EVENT_UNHANDLED_EXC = 2, EXITTHREAD_EVENT_TERMINATE_PROCESS = 3, } -pub type ExitThreadEventReason = Enum_Unnamed13; #[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed14 { - pub reason: u32, +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct ExitThreadEvent { + pub reason: u32_, } -impl ::core::clone::Clone for Struct_Unnamed14 { - fn clone(&self) -> Self { *self } -} -impl ::core::default::Default for Struct_Unnamed14 { +impl ::core::default::Default for ExitThreadEvent { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } -pub type ExitThreadEvent = Struct_Unnamed14; -#[derive(Clone, Copy)] -#[repr(C)] -pub enum Enum_Unnamed15 { +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum UserBreakType { USERBREAK_PANIC = 0, USERBREAK_ASSERT = 1, USERBREAK_USER = 2, } -pub type UserBreakType = Enum_Unnamed15; -#[derive(Clone, Copy)] -#[repr(C)] -pub enum Enum_Unnamed16 { +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum ExceptionEventType { EXC_EVENT_UNDEFINED_INSTRUCTION = 0, EXC_EVENT_UNKNOWN1 = 1, EXC_EVENT_UNKNOWN2 = 2, @@ -185,77 +171,63 @@ pub enum Enum_Unnamed16 { EXC_EVENT_DEBUGGER_BREAK = 7, EXC_EVENT_UNDEFINED_SYSCALL = 8, } -pub type ExceptionEventType = Enum_Unnamed16; #[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed17 { - pub _type: u32, - pub address: u32, - pub argument: u32, -} -impl ::core::clone::Clone for Struct_Unnamed17 { - fn clone(&self) -> Self { *self } -} -impl ::core::default::Default for Struct_Unnamed17 { +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct ExceptionEvent { + pub type_: u32_, + pub address: u32_, + pub argument: u32_, +} +impl ::core::default::Default for ExceptionEvent { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } -pub type ExceptionEvent = Struct_Unnamed17; #[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed18 { - pub clock_tick: u64, +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct SchedulerInOutEvent { + pub clock_tick: u64_, } -impl ::core::clone::Clone for Struct_Unnamed18 { - fn clone(&self) -> Self { *self } -} -impl ::core::default::Default for Struct_Unnamed18 { +impl ::core::default::Default for SchedulerInOutEvent { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } -pub type SchedulerInOutEvent = Struct_Unnamed18; #[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed19 { - pub clock_tick: u64, - pub syscall: u32, -} -impl ::core::clone::Clone for Struct_Unnamed19 { - fn clone(&self) -> Self { *self } -} -impl ::core::default::Default for Struct_Unnamed19 { +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct SyscallInOutEvent { + pub clock_tick: u64_, + pub syscall: u32_, + _bindgen_padding_0_: [u8; 4usize], +} +impl ::core::default::Default for SyscallInOutEvent { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } -pub type SyscallInOutEvent = Struct_Unnamed19; #[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed20 { - pub string_addr: u32, - pub string_size: u32, +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct OutputStringEvent { + pub string_addr: u32_, + pub string_size: u32_, } -impl ::core::clone::Clone for Struct_Unnamed20 { - fn clone(&self) -> Self { *self } -} -impl ::core::default::Default for Struct_Unnamed20 { +impl ::core::default::Default for OutputStringEvent { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } -pub type OutputStringEvent = Struct_Unnamed20; #[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed21 { - pub mapped_addr: u32, - pub mapped_size: u32, - pub memperm: u32, - pub memstate: u32, -} -impl ::core::clone::Clone for Struct_Unnamed21 { - fn clone(&self) -> Self { *self } -} -impl ::core::default::Default for Struct_Unnamed21 { +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct MapEvent { + 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() } } } -pub type MapEvent = Struct_Unnamed21; -#[derive(Clone, Copy)] -#[repr(C)] -pub enum Enum_Unnamed22 { +#[derive(Copy, Clone)] +#[repr(u32)] +#[derive(Debug)] +pub enum DebugEventType { DBG_EVENT_PROCESS = 0, DBG_EVENT_CREATE_THREAD = 1, DBG_EVENT_EXIT_THREAD = 2, @@ -270,16 +242,16 @@ pub enum Enum_Unnamed22 { DBG_EVENT_OUTPUT_STRING = 11, DBG_EVENT_MAP = 12, } -pub type DebugEventType = Enum_Unnamed22; #[repr(C)] -#[derive(Copy)] -pub struct Struct_Unnamed23 { - pub _type: u32, - pub thread_id: u32, - pub unknown: [u32; 2usize], +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct DebugEventInfo { + pub type_: u32_, + pub thread_id: u32_, + pub unknown: [u32_; 2usize], pub _bindgen_data_1_: [u64; 3usize], } -impl Struct_Unnamed23 { +impl DebugEventInfo { pub unsafe fn process(&mut self) -> *mut ProcessEvent { let raw: *mut u8 = ::core::mem::transmute(&self._bindgen_data_1_); ::core::mem::transmute(raw.offset(0)) @@ -317,98 +289,149 @@ impl Struct_Unnamed23 { ::core::mem::transmute(raw.offset(0)) } } -impl ::core::clone::Clone for Struct_Unnamed23 { - fn clone(&self) -> Self { *self } +impl ::core::default::Default for DebugEventInfo { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } } -impl ::core::default::Default for Struct_Unnamed23 { +#[repr(C)] +#[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_, +} +impl ::core::default::Default for CodeSetInfo { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct StartupInfo { + pub priority: ::libc::c_int, + pub stack_size: u32_, + pub argc: ::libc::c_int, + pub argv: *mut u16_, + pub envp: *mut u16_, +} +impl ::core::default::Default for StartupInfo { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } -pub type DebugEventInfo = Struct_Unnamed23; 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 c_void, + dst: *mut ::libc::c_void, srcProcess: Handle, - src: *const c_void, - size: u32, - dmaConfig: *mut c_void) - -> Result; + src: *const ::libc::c_void, size: u32_, + dmaConfig: *mut ::libc::c_void) -> Result; pub fn svcStopDma(dma: Handle) -> Result; - pub fn svcGetDmaState(dmaState: *mut c_void, dma: Handle) + 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 c_void, - size: u32) -> Result; + addr: *mut ::libc::c_void, + size: u32_) -> Result; pub fn svcFlushProcessDataCache(process: Handle, - addr: *const c_void, - size: u32) -> Result; - pub fn svcReadProcessMemory(buffer: *mut c_void, - debug: Handle, addr: u32, size: u32) + addr: *const ::libc::c_void, size: u32_) -> Result; - pub fn svcWriteProcessMemory(debug: Handle, - buffer: *const c_void, - addr: u32, size: u32) -> Result; - pub fn svcOpenProcess(process: *mut Handle, processId: u32) -> Result; + pub fn svcReadProcessMemory(buffer: *mut ::libc::c_void, debug: Handle, + 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; pub fn svcExitProcess(); pub fn svcTerminateProcess(process: Handle) -> Result; - pub fn svcGetProcessInfo(out: *mut s64, 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 s32, processIds: *mut u32, + 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 u8, - maxSessions: s32) -> Result; - pub fn svcConnectToPort(out: *mut Handle, - portName: *const u8) + name: *const ::libc::c_char, maxSessions: s32) + -> Result; + pub fn svcConnectToPort(out: *mut Handle, portName: *const ::libc::c_char) -> Result; + pub fn svcCreateCodeSet(out: *mut Handle, info: *const CodeSetInfo, + code_ptr: *mut ::libc::c_void, + 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; + pub fn svcSetProcessAffinityMask(process: Handle, + 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, + arg: u32_, stack_top: *mut u32_, thread_priority: s32, processor_id: s32) -> Result; - pub fn svcOpenThread(thread: *mut Handle, process: Handle, threadId: u32) + pub fn svcOpenThread(thread: *mut Handle, process: Handle, threadId: u32_) -> Result; pub fn svcExitThread(); 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, + pub fn svcGetThreadAffinityMask(affinitymask: *mut u8_, thread: Handle, processorcount: s32) -> Result; - pub fn svcSetThreadAffinityMask(thread: Handle, affinitymask: *mut u8, + 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: s32) -> Result; pub fn svcGetProcessorID() -> s32; - pub fn svcGetThreadId(out: *mut u32, handle: Handle) -> Result; - pub fn svcGetProcessIdOfThread(out: *mut u32, handle: Handle) -> Result; + pub fn svcGetThreadId(out: *mut u32_, handle: Handle) -> Result; + pub fn svcGetResourceLimit(resourceLimit: *mut Handle, process: Handle) + -> Result; + pub fn svcGetResourceLimitLimitValues(values: *mut s64, + resourceLimit: Handle, + names: *mut u32_, nameCount: s32) + -> Result; + pub fn svcGetResourceLimitCurrentValues(values: *mut s64, + resourceLimit: Handle, + names: *mut u32_, nameCount: s32) + -> Result; + pub fn svcGetProcessIdOfThread(out: *mut u32_, handle: Handle) -> Result; pub fn svcGetThreadInfo(out: *mut s64, thread: Handle, - _type: ThreadInfoType) -> Result; + 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: 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: u8) -> 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: s64) -> Result; @@ -416,35 +439,41 @@ extern "C" { 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: s32, + 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 s32, handles: *mut Handle, handleCount: s32, replyTarget: Handle) -> Result; - pub fn svcCreateTimer(timer: *mut Handle, reset_type: u8) -> Result; + pub fn svcBindInterrupt(interruptId: u32_, event: Handle, priority: s32, + isManualClear: u8) -> 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: 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 s64, _type: u32, param: s32) -> 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 u8, - length: i32) -> Result; - pub fn svcDebugActiveProcess(debug: *mut Handle, processId: u32) + pub fn svcOutputDebugString(str: *const ::libc::c_char, + length: ::libc::c_int) -> Result; + 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 s32>) -> Result; } + +use ::types::*; diff --git a/ctru-sys/src/synchronization.rs b/ctru-sys/src/synchronization.rs index 6715d53..0626394 100644 --- a/ctru-sys/src/synchronization.rs +++ b/ctru-sys/src/synchronization.rs @@ -1,19 +1,40 @@ -//TODO: Implement stuff that bindgen doesn't catch +/* automatically generated by rust-bindgen */ -use Handle; +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] +use Handle; +use svc::ResetType; use super::lock::*; pub type LightLock = _LOCK_T; pub type RecursiveLock = _LOCK_RECURSIVE_T; +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct LightEvent { + pub state: i32, + pub lock: LightLock, +} +impl ::core::default::Default for LightEvent { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} extern "C" { pub fn __sync_get_arbiter() -> Handle; pub fn LightLock_Init(lock: *mut LightLock); - pub fn LightLock_Lock(lock: *mut LightLock); - pub fn LightLock_TryLock(lock: *mut LightLock) -> i32; - pub fn LightLock_Unlock(lock: *mut LightLock); + pub fn LightLock_Lock(lock: *const LightLock); + pub fn LightLock_TryLock(lock: *const LightLock) -> ::libc::c_int; + pub fn LightLock_Unlock(lock: *const LightLock); pub fn RecursiveLock_Init(lock: *mut RecursiveLock); - pub fn RecursiveLock_Lock(lock: *mut RecursiveLock); - pub fn RecursiveLock_TryLock(lock: *mut RecursiveLock) -> i32; - pub fn RecursiveLock_Unlock(lock: *mut RecursiveLock); + pub fn RecursiveLock_Lock(lock: *const RecursiveLock); + pub fn RecursiveLock_TryLock(lock: *const RecursiveLock) -> ::libc::c_int; + pub fn RecursiveLock_Unlock(lock: *const RecursiveLock); + pub fn LightEvent_Init(event: *mut LightEvent, reset_type: ResetType); + pub fn LightEvent_Clear(event: *mut LightEvent); + pub fn LightEvent_Pulse(event: *mut LightEvent); + pub fn LightEvent_Signal(event: *mut LightEvent); + pub fn LightEvent_TryWait(event: *mut LightEvent) -> ::libc::c_int; + pub fn LightEvent_Wait(event: *mut LightEvent); } diff --git a/ctru-sys/src/sys/inaddr.rs b/ctru-sys/src/sys/inaddr.rs new file mode 100644 index 0000000..d188f2c --- /dev/null +++ b/ctru-sys/src/sys/inaddr.rs @@ -0,0 +1,42 @@ +/* automatically generated by rust-bindgen */ + +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] + +use super::socket::*; + +pub type in_port_t = ::libc::uint16_t; +pub type in_addr_t = ::libc::uint32_t; +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct in_addr { + pub s_addr: in_addr_t, +} +impl ::core::default::Default for in_addr { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct sockaddr_in { + pub sin_family: sa_family_t, + pub sin_port: in_port_t, + pub sin_addr: in_addr, + pub sin_zero: [::libc::c_uchar; 8usize], +} +impl ::core::default::Default for sockaddr_in { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, +} +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 b4d4a12..3ae6456 100644 --- a/ctru-sys/src/sys/libc.rs +++ b/ctru-sys/src/sys/libc.rs @@ -1,4 +1,9 @@ -pub const STDOUT_FILENO: i32 = 1; +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] + +pub const STDOUT_FILENO: c_int = 1; #[repr(u8)] pub enum c_void { @@ -6,7 +11,82 @@ pub enum c_void { __variant2, } +pub type c_schar = i8; +pub type c_uchar = u8; +pub type c_char = u8; +pub type c_short = i16; +pub type c_ushort = u16; +pub type c_int = i32; +pub type c_uint = u32; +pub type c_long = i32; +pub type c_ulong = u32; +pub type c_longlong = i64; +pub type c_ulonglong = u64; +pub type c_float = f32; +pub type c_double = f64; +pub type size_t = usize; +pub type ssize_t = isize; + +pub type u_char = c_uchar; +pub type u_short = c_ushort; +pub type u_int = c_uint; +pub type u_long = c_ulong; +pub type ushort = c_ushort; +pub type uint_ = c_uint; +pub type ulong = c_ulong; +pub type clock_t = c_ulong; +pub type time_t = c_long; +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct timespec { + pub tv_sec: time_t, + pub tv_nsec: c_long, +} +impl ::core::default::Default for timespec { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct itimerspec { + pub it_interval: timespec, + pub it_value: timespec, +} +impl ::core::default::Default for itimerspec { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +pub type daddr_t = c_long; +pub type caddr_t = *mut c_char; +pub type ino_t = c_uint; +pub type off_t = c_long; +pub type dev_t = c_int; +pub type uid_t = c_ushort; +pub type gid_t = c_ushort; +pub type pid_t = c_int; +pub type key_t = c_long; +pub type mode_t = c_uint; +pub type nlink_t = c_ushort; +pub type fd_mask = c_long; +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct _types_fd_set { + pub fds_bits: [fd_mask; 1usize], +} +impl ::core::default::Default for _types_fd_set { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +pub type clockid_t = c_ulong; +pub type timer_t = c_ulong; +pub type useconds_t = c_ulong; +pub type suseconds_t = c_long; +pub type fsblkcnt_t = c_uint; +pub type fsfilcnt_t = c_uint; + extern "C" { - pub fn abort() -> !; - pub fn write(fd: i32, buf: *const c_void, count: usize) -> isize; + 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: ::libc::size_t) -> ::libc::ssize_t; } diff --git a/ctru-sys/src/sys/lock.rs b/ctru-sys/src/sys/lock.rs index dcab2d7..0fece83 100644 --- a/ctru-sys/src/sys/lock.rs +++ b/ctru-sys/src/sys/lock.rs @@ -1,20 +1,22 @@ -// from devkitArm, needed for synchronization.rs to compile +/* automatically generated by rust-bindgen */ +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] pub type _LOCK_T = i32; #[repr(C)] -#[derive(Copy)] -pub struct Struct___lock_t { +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct __lock_t { pub lock: _LOCK_T, pub thread_tag: u32, pub counter: u32, } -impl ::core::clone::Clone for Struct___lock_t { - fn clone(&self) -> Self { *self } -} -impl ::core::default::Default for Struct___lock_t { +impl ::core::default::Default for __lock_t { fn default() -> Self { unsafe { ::core::mem::zeroed() } } } -pub type _LOCK_RECURSIVE_T = Struct___lock_t; +pub type _LOCK_RECURSIVE_T = __lock_t; extern "C" { pub fn __libc_lock_init(lock: *mut _LOCK_T); pub fn __libc_lock_init_recursive(lock: *mut _LOCK_RECURSIVE_T); @@ -24,8 +26,7 @@ extern "C" { pub fn __libc_lock_acquire_recursive(lock: *mut _LOCK_RECURSIVE_T); pub fn __libc_lock_release(lock: *mut _LOCK_T); pub fn __libc_lock_release_recursive(lock: *mut _LOCK_RECURSIVE_T); - pub fn __libc_lock_try_acquire(lock: *mut _LOCK_T) - -> i32; + pub fn __libc_lock_try_acquire(lock: *mut _LOCK_T) -> ::libc::c_int; pub fn __libc_lock_try_acquire_recursive(lock: *mut _LOCK_RECURSIVE_T) - -> i32; + -> ::libc::c_int; } diff --git a/ctru-sys/src/sys/mod.rs b/ctru-sys/src/sys/mod.rs index ca421e7..d2d4cbe 100644 --- a/ctru-sys/src/sys/mod.rs +++ b/ctru-sys/src/sys/mod.rs @@ -1,2 +1,3 @@ pub mod lock; -pub mod libc; +pub mod inaddr; +pub mod socket; diff --git a/ctru-sys/src/sys/socket.rs b/ctru-sys/src/sys/socket.rs new file mode 100644 index 0000000..19d1cb1 --- /dev/null +++ b/ctru-sys/src/sys/socket.rs @@ -0,0 +1,75 @@ +/* automatically generated by rust-bindgen */ + +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] +pub type socklen_t = ::libc::uint32_t; +pub type sa_family_t = ::libc::uint16_t; +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct sockaddr { + pub sa_family: sa_family_t, + pub sa_data: [::libc::c_char; 0usize], +} +impl ::core::default::Default for sockaddr { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct sockaddr_storage { + pub ss_family: sa_family_t, + pub __ss_padding: [::libc::c_char; 26usize], +} +impl ::core::default::Default for sockaddr_storage { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct linger { + pub l_onoff: ::libc::c_int, + pub l_linger: ::libc::c_int, +} +impl ::core::default::Default for linger { + fn default() -> Self { unsafe { ::core::mem::zeroed() } } +} +extern "C" { + pub fn accept(sockfd: ::libc::c_int, addr: *mut sockaddr, + addrlen: *mut socklen_t) -> ::libc::c_int; + pub fn bind(sockfd: ::libc::c_int, addr: *const sockaddr, + addrlen: socklen_t) -> ::libc::c_int; + pub fn closesocket(sockfd: ::libc::c_int) -> ::libc::c_int; + pub fn connect(sockfd: ::libc::c_int, addr: *const sockaddr, + addrlen: socklen_t) -> ::libc::c_int; + pub fn getpeername(sockfd: ::libc::c_int, addr: *mut sockaddr, + addrlen: *mut socklen_t) -> ::libc::c_int; + pub fn getsockname(sockfd: ::libc::c_int, addr: *mut sockaddr, + addrlen: *mut socklen_t) -> ::libc::c_int; + pub fn getsockopt(sockfd: ::libc::c_int, level: ::libc::c_int, + optname: ::libc::c_int, optval: *mut ::libc::c_void, + 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: ::libc::size_t, + flags: ::libc::c_int) -> ::libc::ssize_t; + pub fn recvfrom(sockfd: ::libc::c_int, buf: *mut ::libc::c_void, + len: ::libc::size_t, flags: ::libc::c_int, + src_addr: *mut sockaddr, addrlen: *mut socklen_t) + -> ::libc::ssize_t; + pub fn send(sockfd: ::libc::c_int, buf: *const ::libc::c_void, + len: ::libc::size_t, flags: ::libc::c_int) -> ::libc::ssize_t; + pub fn sendto(sockfd: ::libc::c_int, buf: *const ::libc::c_void, + 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; + pub fn shutdown(sockfd: ::libc::c_int, how: ::libc::c_int) + -> ::libc::c_int; + pub fn socket(domain: ::libc::c_int, type_: ::libc::c_int, + protocol: ::libc::c_int) -> ::libc::c_int; + pub fn sockatmark(sockfd: ::libc::c_int) -> ::libc::c_int; +} diff --git a/ctru-sys/src/types.rs b/ctru-sys/src/types.rs index 3861e72..d5baa88 100644 --- a/ctru-sys/src/types.rs +++ b/ctru-sys/src/types.rs @@ -1,35 +1,27 @@ -#[repr(C)] -pub enum mediatypes_enum { - mediatype_NAND = 0, - mediatype_SDMC = 1, - mediatype_GAMECARD = 2, -} +/* automatically generated by rust-bindgen */ +#![allow(dead_code, + non_camel_case_types, + non_upper_case_globals, + non_snake_case)] +pub type u8_ = u8; +pub type u16_ = u16; +pub type u32_ = u32; +pub type u64_ = u64; pub type s8 = i8; pub type s16 = i16; pub type s32 = i32; pub type s64 = i64; - -// UHH, DUNNO HOW TO USE VOLATILES ???? -pub type vu8 = u8; -pub type vu32 = u32; - -// typedef uint8_t u8; -// typedef uint16_t u16; -// typedef uint32_t u32; -// typedef uint64_t u64; -// -// typedef int8_t s8; -// typedef int16_t s16; -// typedef int32_t s32; -// typedef int64_t s64; -// -// typedef volatile u8 vu8; -// typedef volatile u16 vu16; -// typedef volatile u32 vu32; -// typedef volatile u64 vu64; -// -// typedef volatile s8 vs8; -// typedef volatile s16 vs16; -// typedef volatile s32 vs32; -// typedef volatile s64 vs64; +pub type vu8 = u8_; +pub type vu16 = u16_; +pub type vu32 = u32_; +pub type vu64 = u64_; +pub type vs8 = s8; +pub type vs16 = s16; +pub type vs32 = s32; +pub type vs64 = s64; +pub type Handle = u32_; +pub type Result = s32; +pub type ThreadFunc = + ::core::option::Option; +pub type voidfn = ::core::option::Option; diff --git a/src/console.rs b/src/console.rs deleted file mode 100644 index 6e05ec2..0000000 --- a/src/console.rs +++ /dev/null @@ -1,50 +0,0 @@ -use libctru::console::*; -use libctru::libc; - -use gfx::Screen; - -use core::fmt::{self, Write}; -use core::default::Default; -use core::ptr; - -pub struct Console { - context: PrintConsole, -} - -impl Console { - pub fn init(screen: Screen) -> Self { - let ret = unsafe { *(consoleInit(screen.into(), ptr::null_mut())) }; - Console { context: ret } - } - - pub fn set_window(&mut self, x: i32, y: i32, width: i32, height: i32) { - unsafe { consoleSetWindow(&mut self.context, x, y, width, height) } - } - - pub fn clear(&mut self) { - unsafe { consoleClear() } - } -} - -impl Default for Console { - fn default() -> Self { - let ret = unsafe { *(consoleInit(Screen::Top.into(), ptr::null_mut())) }; - Console { context: ret } - } -} - -impl Write for Console { - fn write_str(&mut self, s: &str) -> fmt::Result { - // Writing 0 bytes to the console fails - if s.is_empty() { - return Ok(()) - } - unsafe { consoleSelect(&mut self.context); } - let ret = unsafe { libc::write(libc::STDOUT_FILENO, s.as_ptr() as *const _, s.len()) }; - if ret == s.len() as isize { - Ok(()) - } else { - Err(fmt::Error) - } - } -} diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs deleted file mode 100644 index 3a2d5f1..0000000 --- a/src/ffi/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub use self::os_str::{OsString, OsStr}; - -mod os_str; diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 14702af..0000000 --- a/src/lib.rs +++ /dev/null @@ -1,37 +0,0 @@ -#![feature(alloc)] -#![feature(collections)] -#![feature(char_escape_debug)] -#![feature(lang_items)] -#![feature(question_mark)] -#![feature(slice_patterns)] -#![feature(str_internals)] -#![feature(unicode)] - -#![no_std] - -#![crate_type = "rlib"] -#![crate_name = "ctru"] - -extern crate alloc; -extern crate alloc_system; -extern crate collections; -extern crate rustc_unicode; - -extern crate ctru_sys as libctru; - -pub mod console; -pub mod srv; -pub mod gfx; -pub mod services; -pub mod sdmc; - -pub mod ascii; -pub mod ffi; -pub mod panic; -pub mod path; - -mod sys; - -pub use srv::Srv; -pub use gfx::Gfx; -pub use sdmc::Sdmc; diff --git a/src/services/apt.rs b/src/services/apt.rs deleted file mode 100644 index 69094b2..0000000 --- a/src/services/apt.rs +++ /dev/null @@ -1,84 +0,0 @@ -use core::marker::PhantomData; - -use libctru::services::apt; - -pub enum AppStatus { - NotInitialized, - Running, - Suspended, - Exiting, - Suspending, - SleepMode, - PrepareSleepMode, - AppletStarted, - AppletClosed, -} - -impl From for apt::APT_AppStatus { - fn from(a: AppStatus) -> apt::APT_AppStatus { - use self::AppStatus::*; - use libctru::services::apt::APT_AppStatus::*; - match a { - NotInitialized => APP_NOTINITIALIZED, - Running => APP_RUNNING, - Suspended => APP_SUSPENDED, - Exiting => APP_EXITING, - Suspending => APP_SUSPENDING, - SleepMode => APP_SLEEPMODE, - PrepareSleepMode => APP_PREPARE_SLEEPMODE, - AppletStarted => APP_APPLETSTARTED, - AppletClosed => APP_APPLETCLOSED, - } - } -} - -impl From for AppStatus { - fn from(a: apt::APT_AppStatus) -> AppStatus { - use self::AppStatus::*; - use libctru::services::apt::APT_AppStatus::*; - match a { - APP_NOTINITIALIZED => NotInitialized, - APP_RUNNING => Running, - APP_SUSPENDED => Suspended, - APP_EXITING => Exiting, - APP_SUSPENDING => Suspending, - APP_SLEEPMODE => SleepMode, - APP_PREPARE_SLEEPMODE => PrepareSleepMode, - APP_APPLETSTARTED => AppletStarted, - APP_APPLETCLOSED => AppletClosed, - } - } -} - -pub struct Apt { - pd: PhantomData -} - -impl Apt { - pub fn init() -> Result { - unsafe { - let r = apt::aptInit(); - if r < 0 { - Err(r) - } else { - Ok(Apt { pd: PhantomData }) - } - } - } - - pub fn main_loop(&self) -> bool { - unsafe { - match apt::aptMainLoop() { - 1 => true, - 0 => false, - _ => unreachable!(), - } - } - } -} - -impl Drop for Apt { - fn drop(&mut self) { - unsafe { apt::aptExit() }; - } -} diff --git a/src/sys/mod.rs b/src/sys/mod.rs deleted file mode 100644 index 86f49e5..0000000 --- a/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/src/sys/wtf8.rs b/src/sys/wtf8.rs deleted file mode 100644 index 12ca7a1..0000000 --- a/src/sys/wtf8.rs +++ /dev/null @@ -1,1206 +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 collections::borrow::Cow; -use rustc_unicode::char; -use core::fmt; -use core::hash::{Hash, Hasher}; -use core::iter::FromIterator; -use core::mem; -use core::ops; -use collections::slice; -use core::str; -use collections::String; -use sys::AsInner; -use collections::Vec; - -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]); - } -}