From eec80b496b8de2ee332b4ae04fbe00c7c93525b3 Mon Sep 17 00:00:00 2001 From: Fenrir Date: Fri, 7 Jul 2017 11:39:39 -0600 Subject: [PATCH 1/3] Use libc from crates.io The libc crate has newlib bindings now, so we don't have to maintain them in-tree anymore --- ctr-libc/Cargo.toml | 14 -- ctr-libc/README.md | 1 - ctr-libc/src/constants.rs | 131 ------------------ ctr-libc/src/functions.rs | 39 ------ ctr-libc/src/lib.rs | 177 ------------------------ ctr-std/Cargo.toml | 7 +- ctr-std/src/lib.rs | 2 +- ctr-std/src/sys/unix/memchr.rs | 21 +-- ctr-std/src/sys_common/memchr.rs | 230 +++++++++++++++++++++++++++++++ ctr-std/src/sys_common/mod.rs | 5 +- ctru-sys/Cargo.toml | 5 +- ctru-sys/src/lib.rs | 2 +- 12 files changed, 244 insertions(+), 390 deletions(-) delete mode 100644 ctr-libc/Cargo.toml delete mode 100644 ctr-libc/README.md delete mode 100644 ctr-libc/src/constants.rs delete mode 100644 ctr-libc/src/functions.rs delete mode 100644 ctr-libc/src/lib.rs create mode 100644 ctr-std/src/sys_common/memchr.rs diff --git a/ctr-libc/Cargo.toml b/ctr-libc/Cargo.toml deleted file mode 100644 index 5bc4c6b..0000000 --- a/ctr-libc/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[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 deleted file mode 100644 index ce5eb41..0000000 --- a/ctr-libc/README.md +++ /dev/null @@ -1 +0,0 @@ -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 deleted file mode 100644 index 7da4842..0000000 --- a/ctr-libc/src/constants.rs +++ /dev/null @@ -1,131 +0,0 @@ -// 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 S_IFIFO: ::mode_t = 4096; -pub const S_IFCHR: ::mode_t = 8192; -pub const S_IFDIR: ::mode_t = 16384; -pub const S_IFBLK: ::mode_t = 24576; -pub const S_IFREG: ::mode_t = 32768; -pub const S_IFLNK: ::mode_t = 40960; -pub const S_IFSOCK: ::mode_t = 49152; -pub const S_IFMT: ::mode_t = 61440; - -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 deleted file mode 100644 index a0d21ac..0000000 --- a/ctr-libc/src/functions.rs +++ /dev/null @@ -1,39 +0,0 @@ -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 deleted file mode 100644 index 50ead9d..0000000 --- a/ctr-libc/src/lib.rs +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(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/ctr-std/Cargo.toml b/ctr-std/Cargo.toml index b7f6da1..8f3bb7e 100644 --- a/ctr-std/Cargo.toml +++ b/ctr-std/Cargo.toml @@ -6,11 +6,12 @@ license = "MIT/Apache 2.0" [dependencies.compiler_builtins] git = "https://github.com/rust-lang-nursery/compiler-builtins" -[dependencies.ctr-libc] -path = "../ctr-libc" +[dependencies.libc] +version = "0.2" +default-features = false [dependencies.ctru-sys] path = "../ctru-sys" [dependencies.alloc_system] -version = "0.1.1" +version = "0.1" diff --git a/ctr-std/src/lib.rs b/ctr-std/src/lib.rs index 7a520b8..de28fc1 100644 --- a/ctr-std/src/lib.rs +++ b/ctr-std/src/lib.rs @@ -63,12 +63,12 @@ extern crate collections as core_collections; extern crate alloc; extern crate std_unicode; extern crate alloc_system; +extern crate libc; // compiler-rt intrinsics extern crate compiler_builtins; // 3ds-specific dependencies -extern crate ctr_libc as libc; extern crate ctru_sys as libctru; // The standard macros that are not built-in to the compiler. diff --git a/ctr-std/src/sys/unix/memchr.rs b/ctr-std/src/sys/unix/memchr.rs index d7e9c2b..ae8e3d0 100644 --- a/ctr-std/src/sys/unix/memchr.rs +++ b/ctr-std/src/sys/unix/memchr.rs @@ -28,24 +28,11 @@ pub fn memchr(needle: u8, haystack: &[u8]) -> Option { } pub fn memrchr(needle: u8, haystack: &[u8]) -> Option { - - #[cfg(target_os = "linux")] + // turns out that newlib doesn't have memrchr(), so we + // use the fallback version instead 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)) - } + ::sys_common::memchr::fallback::memrchr(needle, haystack) } + memrchr_specific(needle, haystack) } diff --git a/ctr-std/src/sys_common/memchr.rs b/ctr-std/src/sys_common/memchr.rs new file mode 100644 index 0000000..3824a5f --- /dev/null +++ b/ctr-std/src/sys_common/memchr.rs @@ -0,0 +1,230 @@ +// 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 + +#[allow(dead_code)] +pub mod fallback { + use cmp; + use mem; + + const LO_U64: u64 = 0x0101010101010101; + const HI_U64: u64 = 0x8080808080808080; + + // use truncation + const LO_USIZE: usize = LO_U64 as usize; + const HI_USIZE: usize = HI_U64 as usize; + + /// Return `true` if `x` contains any zero byte. + /// + /// From *Matters Computational*, J. Arndt + /// + /// "The idea is to subtract one from each of the bytes and then look for + /// bytes where the borrow propagated all the way to the most significant + /// bit." + #[inline] + fn contains_zero_byte(x: usize) -> bool { + x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0 + } + + #[cfg(target_pointer_width = "32")] + #[inline] + fn repeat_byte(b: u8) -> usize { + let mut rep = (b as usize) << 8 | b as usize; + rep = rep << 16 | rep; + rep + } + + #[cfg(target_pointer_width = "64")] + #[inline] + fn repeat_byte(b: u8) -> usize { + let mut rep = (b as usize) << 8 | b as usize; + rep = rep << 16 | rep; + rep = rep << 32 | rep; + rep + } + + /// Return the first index matching the byte `a` in `text`. + pub fn memchr(x: u8, text: &[u8]) -> Option { + // Scan for a single byte value by reading two `usize` words at a time. + // + // Split `text` in three parts + // - unaligned initial part, before the first word aligned address in text + // - body, scan by 2 words at a time + // - the last remaining part, < 2 word size + let len = text.len(); + let ptr = text.as_ptr(); + let usize_bytes = mem::size_of::(); + + // search up to an aligned boundary + let align = (ptr as usize) & (usize_bytes- 1); + let mut offset; + if align > 0 { + offset = cmp::min(usize_bytes - align, len); + if let Some(index) = text[..offset].iter().position(|elt| *elt == x) { + return Some(index); + } + } else { + offset = 0; + } + + // search the body of the text + let repeated_x = repeat_byte(x); + + if len >= 2 * usize_bytes { + while offset <= len - 2 * usize_bytes { + unsafe { + let u = *(ptr.offset(offset as isize) as *const usize); + let v = *(ptr.offset((offset + usize_bytes) as isize) as *const usize); + + // break if there is a matching byte + let zu = contains_zero_byte(u ^ repeated_x); + let zv = contains_zero_byte(v ^ repeated_x); + if zu || zv { + break; + } + } + offset += usize_bytes * 2; + } + } + + // find the byte after the point the body loop stopped + text[offset..].iter().position(|elt| *elt == x).map(|i| offset + i) + } + + /// Return the last index matching the byte `a` in `text`. + pub fn memrchr(x: u8, text: &[u8]) -> Option { + // Scan for a single byte value by reading two `usize` words at a time. + // + // Split `text` in three parts + // - unaligned tail, after the last word aligned address in text + // - body, scan by 2 words at a time + // - the first remaining bytes, < 2 word size + let len = text.len(); + let ptr = text.as_ptr(); + let usize_bytes = mem::size_of::(); + + // search to an aligned boundary + let end_align = (ptr as usize + len) & (usize_bytes - 1); + let mut offset; + if end_align > 0 { + offset = if end_align >= len { 0 } else { len - end_align }; + if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) { + return Some(offset + index); + } + } else { + offset = len; + } + + // search the body of the text + let repeated_x = repeat_byte(x); + + while offset >= 2 * usize_bytes { + unsafe { + let u = *(ptr.offset(offset as isize - 2 * usize_bytes as isize) as *const usize); + let v = *(ptr.offset(offset as isize - usize_bytes as isize) as *const usize); + + // break if there is a matching byte + let zu = contains_zero_byte(u ^ repeated_x); + let zv = contains_zero_byte(v ^ repeated_x); + if zu || zv { + break; + } + } + offset -= 2 * usize_bytes; + } + + // find the byte before the point the body loop stopped + text[..offset].iter().rposition(|elt| *elt == x) + } + + // test fallback implementations on all platforms + #[test] + fn matches_one() { + assert_eq!(Some(0), memchr(b'a', b"a")); + } + + #[test] + fn matches_begin() { + assert_eq!(Some(0), memchr(b'a', b"aaaa")); + } + + #[test] + fn matches_end() { + assert_eq!(Some(4), memchr(b'z', b"aaaaz")); + } + + #[test] + fn matches_nul() { + assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00")); + } + + #[test] + fn matches_past_nul() { + assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z")); + } + + #[test] + fn no_match_empty() { + assert_eq!(None, memchr(b'a', b"")); + } + + #[test] + fn no_match() { + assert_eq!(None, memchr(b'a', b"xyz")); + } + + #[test] + fn matches_one_reversed() { + assert_eq!(Some(0), memrchr(b'a', b"a")); + } + + #[test] + fn matches_begin_reversed() { + assert_eq!(Some(3), memrchr(b'a', b"aaaa")); + } + + #[test] + fn matches_end_reversed() { + assert_eq!(Some(0), memrchr(b'z', b"zaaaa")); + } + + #[test] + fn matches_nul_reversed() { + assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00")); + } + + #[test] + fn matches_past_nul_reversed() { + assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa")); + } + + #[test] + fn no_match_empty_reversed() { + assert_eq!(None, memrchr(b'a', b"")); + } + + #[test] + fn no_match_reversed() { + assert_eq!(None, memrchr(b'a', b"xyz")); + } + + #[test] + fn each_alignment_reversed() { + let mut data = [1u8; 64]; + let needle = 2; + let pos = 40; + data[pos] = needle; + for start in 0..16 { + assert_eq!(Some(pos - start), memrchr(needle, &data[start..])); + } + } +} diff --git a/ctr-std/src/sys_common/mod.rs b/ctr-std/src/sys_common/mod.rs index 936ff80..6f47466 100644 --- a/ctr-std/src/sys_common/mod.rs +++ b/ctr-std/src/sys_common/mod.rs @@ -27,6 +27,7 @@ pub mod at_exit_imp; pub mod condvar; pub mod io; +pub mod memchr; pub mod mutex; pub mod poison; pub mod remutex; @@ -76,10 +77,6 @@ pub fn at_exit(f: F) -> Result<(), ()> { if at_exit_imp::push(Box::new(f)) {Ok(())} else {Err(())} } -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). diff --git a/ctru-sys/Cargo.toml b/ctru-sys/Cargo.toml index 99e347b..38eeca8 100644 --- a/ctru-sys/Cargo.toml +++ b/ctru-sys/Cargo.toml @@ -4,5 +4,6 @@ version = "0.3.0" authors = ["Ronald Kinard "] license = "https://en.wikipedia.org/wiki/Zlib_License" -[dependencies] -ctr-libc = { path = "../ctr-libc" } +[dependencies.libc] +version = "0.2" +default-features = false diff --git a/ctru-sys/src/lib.rs b/ctru-sys/src/lib.rs index 5bbc54d..d2b54aa 100644 --- a/ctru-sys/src/lib.rs +++ b/ctru-sys/src/lib.rs @@ -8,7 +8,7 @@ #![allow(non_camel_case_types, non_snake_case, overflowing_literals)] #![feature(untagged_unions)] -extern crate ctr_libc as libc; +extern crate libc; pub mod applets; pub mod console; From 4b5b6223c5b77b9c0db1f3ff28c79800841c9643 Mon Sep 17 00:00:00 2001 From: Fenrir Date: Fri, 7 Jul 2017 12:21:12 -0600 Subject: [PATCH 2/3] ctru-rs: workaround for xargo/sysroot issue Both our implementation of std and ctru-rs depend on the libc crate (or rather, ctru-rs depends on ctru-sys which depends on libc). This means that libc ends up both in the sysroot assembled by Xargo, as well as being built as a regular dependency for ctru-rs. However, it seems that when cargo/rustc tries to link the libc crate to ctru-rs, it first searches in the sysroot and links in the copy that it finds there, rather than the one specified in ctru-rs's Cargo.toml. rust-lang's rustbuild system does some trickery with crate metadata to avoid this sort of name collision between the sysroot and user deps, but xargo does not (yet) do something similar. And since rustc now enforces that linking to any crate from the sysroot is an unstable operation, the result is a rather cryptic compiler error. Fortunately we can work around this by simply tagging ctru-rs with #![feature(rustc_private)], but it shouldn't be regarded as a long-term fix --- ctru-rs/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ctru-rs/src/lib.rs b/ctru-rs/src/lib.rs index 10132a0..355c59f 100644 --- a/ctru-rs/src/lib.rs +++ b/ctru-rs/src/lib.rs @@ -1,6 +1,9 @@ #![crate_type = "rlib"] #![crate_name = "ctru"] +// Temporary workaround for a Xargo(?) issue +#![feature(rustc_private)] + #[macro_use] extern crate bitflags; extern crate widestring; From 30c52fc9de4532999553695b2c39706c91dac525 Mon Sep 17 00:00:00 2001 From: Fenrir Date: Fri, 7 Jul 2017 18:13:28 -0600 Subject: [PATCH 3/3] Update README --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 4c59d03..18a7aeb 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,6 @@ 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