Nightly stuff
This commit is contained in:
parent
5b449f4e1e
commit
fd2384b7fa
9 changed files with 73 additions and 232 deletions
1
rustfmt.toml
Normal file
1
rustfmt.toml
Normal file
|
@ -0,0 +1 @@
|
|||
hard_tabs = true
|
|
@ -1,150 +0,0 @@
|
|||
use crate::util;
|
||||
|
||||
use core::{fmt, mem, ptr};
|
||||
use core::ops::{Deref, DerefMut};
|
||||
|
||||
fn alloc<T>(len: usize) -> *mut T {
|
||||
if util::zst::<T>(len) {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let size = len.checked_mul(mem::size_of::<T>()).expect("allocation overflow");
|
||||
let align = mem::align_of::<T>();
|
||||
util::must_succeed(
|
||||
unsafe {
|
||||
libc::memalign(align, size)
|
||||
}
|
||||
).cast()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
const fn dangling<T>() -> *mut T {
|
||||
mem::align_of::<T>() as *mut T
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn slice_len<T>(p: *const [T]) -> usize {
|
||||
unsafe { mem::transmute::<_, [usize; 2]>(p)[1] }
|
||||
}
|
||||
|
||||
pub trait SafePtr {
|
||||
fn safe_ptr(p: *mut Self) -> *mut Self;
|
||||
}
|
||||
|
||||
impl<T> SafePtr for T {
|
||||
#[inline]
|
||||
fn safe_ptr(p: *mut T) -> *mut T {
|
||||
if util::zst::<T>(1) {
|
||||
return dangling();
|
||||
}
|
||||
|
||||
debug_assert!(!p.is_null(), "NULL ptr");
|
||||
p
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SafePtr for [T] {
|
||||
#[inline]
|
||||
fn safe_ptr(p: *mut [T]) -> *mut [T] {
|
||||
let len = slice_len(p);
|
||||
if util::zst::<T>(len) {
|
||||
return ptr::slice_from_raw_parts_mut(dangling(), len);
|
||||
}
|
||||
|
||||
debug_assert!(!p.is_null(), "NULL ptr");
|
||||
p
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CBox<T: SafePtr + ?Sized>(*mut T);
|
||||
|
||||
impl<T: SafePtr + ?Sized> CBox<T> {
|
||||
#[inline]
|
||||
pub unsafe fn from_raw_unchecked(p: *mut T) -> CBox<T> {
|
||||
CBox(p)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn into_raw(self) -> *mut T {
|
||||
let p = self.0;
|
||||
mem::forget(self);
|
||||
p
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_ptr(&self) -> *const T {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_mut_ptr(&mut self) -> *mut T {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> CBox<T> {
|
||||
#[inline]
|
||||
pub fn new(value: T) -> CBox<T> {
|
||||
let p = alloc(1);
|
||||
unsafe {
|
||||
ptr::write(p, value);
|
||||
CBox::from_raw_unchecked(p)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn from_raw(p: *mut T) -> CBox<T> {
|
||||
util::check_ptr(p, 1);
|
||||
CBox(p)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn slice_from_raw_parts_unchecked(p: *mut T, len: usize) -> CBox<[T]> {
|
||||
CBox(ptr::slice_from_raw_parts_mut(p, len))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn slice_from_raw_parts(p: *mut T, len: usize) -> CBox<[T]> {
|
||||
util::check_ptr(p, len);
|
||||
CBox::slice_from_raw_parts_unchecked(p, len)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: SafePtr + ?Sized> Drop for CBox<T> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
ptr::drop_in_place(self.0);
|
||||
libc::free(self.0.cast());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: SafePtr + ?Sized> Deref for CBox<T> {
|
||||
type Target = T;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &T {
|
||||
unsafe { &*T::safe_ptr(self.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: SafePtr + ?Sized> DerefMut for CBox<T> {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
unsafe { &mut *T::safe_ptr(self.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug + SafePtr + ?Sized> fmt::Debug for CBox<T> {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Display + SafePtr + ?Sized> fmt::Display for CBox<T> {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Display::fmt(&**self, f)
|
||||
}
|
||||
}
|
|
@ -6,9 +6,14 @@ use core::fmt;
|
|||
#[repr(transparent)]
|
||||
pub struct Errno(pub libc::c_int);
|
||||
|
||||
extern "C" {
|
||||
//#[ffi_const]
|
||||
pub fn __errno_location() -> *mut libc::c_int;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn errno() -> Errno {
|
||||
unsafe { Errno(*libc::__errno_location()) }
|
||||
unsafe { Errno(*__errno_location()) }
|
||||
}
|
||||
|
||||
impl fmt::Display for Errno {
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
#![no_std]
|
||||
#![feature(slice_ptr_len)]
|
||||
#![feature(min_specialization)]
|
||||
// #![feature(ffi_const)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
pub use libc::*;
|
||||
|
||||
mod util;
|
||||
|
||||
pub mod boxed;
|
||||
pub mod errno;
|
||||
pub mod stdio;
|
||||
pub mod string;
|
||||
|
||||
|
||||
extern "C" {
|
||||
pub fn strndup(cs: *const libc::c_char, n: libc::size_t) -> *mut libc::c_char;
|
||||
|
||||
|
|
|
@ -41,28 +41,17 @@ pub fn stderr() -> Stderr {
|
|||
impl BasicOStream {
|
||||
#[inline]
|
||||
pub fn flush(&mut self) -> Result<()> {
|
||||
check_io(unsafe {
|
||||
libc::fflush(self.0)
|
||||
} == 0)
|
||||
check_io(unsafe { libc::fflush(self.0) } == 0)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn write(&mut self, b: &[u8]) -> Result<()> {
|
||||
check_io(unsafe {
|
||||
libc::fwrite(
|
||||
b.as_ptr().cast(),
|
||||
1,
|
||||
b.len(),
|
||||
self.0,
|
||||
)
|
||||
} == b.len())
|
||||
check_io(unsafe { libc::fwrite(b.as_ptr().cast(), 1, b.len(), self.0) } == b.len())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn puts(&mut self, s: &string::CStr) -> Result<()> {
|
||||
check_io(unsafe {
|
||||
libc::fputs(s.as_ptr(), self.0)
|
||||
} != libc::EOF)
|
||||
check_io(unsafe { libc::fputs(s.as_ptr(), self.0) } != libc::EOF)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,39 +1,29 @@
|
|||
use crate::{self as libc, util, boxed::CBox};
|
||||
use crate::{self as libc, util};
|
||||
|
||||
use core::slice;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use alloc::boxed::Box;
|
||||
use core::{ops::{Deref, DerefMut}, slice};
|
||||
|
||||
//pub struct FromBytesWithNulError {}
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct CStr { inner: libc::c_char }
|
||||
pub struct CStr {
|
||||
inner: libc::c_char,
|
||||
}
|
||||
|
||||
impl CStr {
|
||||
#[inline]
|
||||
pub unsafe fn from_ptr_unchecked<'a>(p: *const libc::c_char) -> &'a CStr {
|
||||
pub unsafe fn from_ptr<'a>(p: *const libc::c_char) -> &'a CStr {
|
||||
&*p.cast()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn from_ptr<'a>(p: *const libc::c_char) -> &'a CStr {
|
||||
util::check_ptr(p, 1);
|
||||
CStr::from_ptr_unchecked(p)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn from_mut_ptr_unchecked<'a>(p: *mut libc::c_char) -> &'a mut CStr {
|
||||
pub unsafe fn from_mut_ptr<'a>(p: *mut libc::c_char) -> &'a mut CStr {
|
||||
&mut *p.cast()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn from_mut_ptr<'a>(p: *mut libc::c_char) -> &'a mut CStr {
|
||||
util::check_ptr(p, 1);
|
||||
CStr::from_mut_ptr_unchecked(p)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
|
||||
CStr::from_ptr_unchecked(bytes.as_ptr().cast())
|
||||
CStr::from_ptr(bytes.as_ptr().cast())
|
||||
}
|
||||
|
||||
// TODO
|
||||
|
@ -57,18 +47,12 @@ impl CStr {
|
|||
|
||||
#[inline]
|
||||
pub fn to_bytes(&self) -> &[u8] {
|
||||
unsafe { slice::from_raw_parts(
|
||||
self.as_ptr().cast(),
|
||||
self.len(),
|
||||
) }
|
||||
unsafe { slice::from_raw_parts(self.as_ptr().cast(), self.len()) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_mut_bytes(&mut self) -> &mut [u8] {
|
||||
unsafe { slice::from_raw_parts_mut(
|
||||
self.as_mut_ptr().cast(),
|
||||
self.len(),
|
||||
) }
|
||||
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr().cast(), self.len()) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -89,28 +73,26 @@ impl CStr {
|
|||
|
||||
#[macro_export]
|
||||
macro_rules! cstr {
|
||||
($s:expr) => (
|
||||
($s:expr) => {
|
||||
unsafe { $crate::string::CStr::from_bytes_with_nul_unchecked(concat!($s, "\0").as_bytes()) }
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
pub struct CString { inner: CBox<libc::c_char> }
|
||||
pub struct CString {
|
||||
inner: Box<libc::c_char>,
|
||||
}
|
||||
|
||||
impl CString {
|
||||
#[inline]
|
||||
pub unsafe fn from_raw_unchecked(p: *mut libc::c_char) -> CString {
|
||||
CString { inner: CBox::from_raw_unchecked(p) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn from_raw(p: *mut libc::c_char) -> CString {
|
||||
util::check_ptr(p, 1);
|
||||
CString::from_raw_unchecked(p)
|
||||
CString {
|
||||
inner: Box::from_raw(p),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn into_raw(self) -> *mut libc::c_char {
|
||||
self.inner.into_raw()
|
||||
Box::into_raw(self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,12 +115,10 @@ impl DerefMut for CString {
|
|||
impl From<&[u8]> for CString {
|
||||
fn from(s: &[u8]) -> CString {
|
||||
unsafe {
|
||||
CString::from_raw_unchecked(
|
||||
util::must_succeed(libc::strndup(
|
||||
CString::from_raw(util::must_succeed(libc::strndup(
|
||||
s.as_ptr().cast(),
|
||||
s.len(),
|
||||
))
|
||||
)
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -153,8 +133,6 @@ impl From<&str> for CString {
|
|||
impl From<&CStr> for CString {
|
||||
#[inline]
|
||||
fn from(s: &CStr) -> CString {
|
||||
unsafe {
|
||||
CString::from_raw_unchecked(util::must_succeed(libc::strdup(s.as_ptr())))
|
||||
}
|
||||
unsafe { CString::from_raw(util::must_succeed(libc::strdup(s.as_ptr()))) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,3 @@
|
|||
use core::mem;
|
||||
|
||||
#[inline]
|
||||
pub fn zst<T>(len: usize) -> bool {
|
||||
mem::size_of::<T>() == 0 || len == 0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn check_ptr<T>(p: *const T, len: usize) {
|
||||
debug_assert!((p as usize) % mem::align_of::<T>() == 0, "unaligned ptr");
|
||||
assert!(zst::<T>(len) || !p.is_null(), "NULL ptr");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn must_succeed<T>(p: *mut T) -> *mut T {
|
||||
assert!(!p.is_null(), "allocation failure");
|
||||
|
|
17
src/main.rs
17
src/main.rs
|
@ -1,8 +1,12 @@
|
|||
#![no_main]
|
||||
#![no_std]
|
||||
#![feature(alloc_error_handler)]
|
||||
|
||||
use safe_libc as libc;
|
||||
mod system_alloc;
|
||||
|
||||
extern crate alloc;
|
||||
use libc::cstr;
|
||||
use safe_libc as libc;
|
||||
|
||||
use core::fmt::Write;
|
||||
|
||||
|
@ -19,17 +23,20 @@ pub extern "C" fn main(_nargs: libc::c_int, _args: *const *const libc::c_char) -
|
|||
let x = libc::string::CString::from("foo");
|
||||
let l = x.len();
|
||||
let y = x.into_raw();
|
||||
let z = unsafe {
|
||||
libc::boxed::CBox::slice_from_raw_parts(y, l)
|
||||
};
|
||||
let z = unsafe { alloc::boxed::Box::from_raw(core::ptr::slice_from_raw_parts_mut(y, l)) };
|
||||
let _ = writeln!(stdout, "Foo: {} {} {}", z[0], z[1], z[2]);
|
||||
}
|
||||
|
||||
{
|
||||
let b = libc::boxed::CBox::new(42);
|
||||
let b = alloc::boxed::Box::new(42);
|
||||
let _ = writeln!(stdout, "Bar: {}", b);
|
||||
}
|
||||
|
||||
{
|
||||
let x = alloc::boxed::Box::new(());
|
||||
let _ = writeln!(stdout, "Box: {:?}", x);
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
|
|
21
src/system_alloc.rs
Normal file
21
src/system_alloc.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
use safe_libc as libc;
|
||||
|
||||
struct System;
|
||||
|
||||
unsafe impl alloc::alloc::GlobalAlloc for System {
|
||||
unsafe fn alloc(&self, layout: alloc::alloc::Layout) -> *mut u8 {
|
||||
libc::memalign(layout.align(), layout.size()).cast()
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, _layout: alloc::alloc::Layout) {
|
||||
libc::free(ptr.cast());
|
||||
}
|
||||
}
|
||||
|
||||
#[global_allocator]
|
||||
static SYSTEM_ALLOC: System = System;
|
||||
|
||||
#[alloc_error_handler]
|
||||
fn alloc_error(_: core::alloc::Layout) -> ! {
|
||||
panic!("allocation failure");
|
||||
}
|
Reference in a new issue