Compare commits
10 commits
fff906a78b
...
58260af4d8
Author | SHA1 | Date | |
---|---|---|---|
58260af4d8 | |||
554275d781 | |||
daf595fe56 | |||
806ba1d0a8 | |||
85d52f3db6 | |||
acafb83a63 | |||
4f5b90400e | |||
a205bbb1d2 | |||
fd2384b7fa | |||
5b449f4e1e |
12 changed files with 264 additions and 237 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -2,9 +2,9 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.68"
|
version = "0.2.71"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0"
|
checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "neco"
|
name = "neco"
|
||||||
|
|
1
rustfmt.toml
Normal file
1
rustfmt.toml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
hard_tabs = true
|
14
safe_libc/Cargo.lock
generated
14
safe_libc/Cargo.lock
generated
|
@ -1,14 +0,0 @@
|
||||||
# This file is automatically @generated by Cargo.
|
|
||||||
# It is not intended for manual editing.
|
|
||||||
[[package]]
|
|
||||||
name = "libc"
|
|
||||||
version = "0.2.68"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "safe_libc"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
|
@ -7,4 +7,4 @@ edition = "2018"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libc = { version = "0.2.68", default-features = false }
|
libc = { version = "0.2.71", default-features = false }
|
||||||
|
|
|
@ -1,150 +1,78 @@
|
||||||
use crate::util;
|
use core::{marker, mem, ptr};
|
||||||
|
|
||||||
use core::{fmt, mem, ptr};
|
|
||||||
use core::ops::{Deref, DerefMut};
|
use core::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
fn alloc<T>(len: usize) -> *mut T {
|
pub trait Dealloc<T: ?Sized> {
|
||||||
if util::zst::<T>(len) {
|
unsafe fn dealloc(p: *mut T);
|
||||||
return ptr::null_mut();
|
|
||||||
}
|
}
|
||||||
let size = len.checked_mul(mem::size_of::<T>()).expect("allocation overflow");
|
|
||||||
let align = mem::align_of::<T>();
|
#[repr(transparent)]
|
||||||
util::must_succeed(
|
pub struct BoxLike<T: ?Sized, D: Dealloc<T>> {
|
||||||
unsafe {
|
inner: ptr::NonNull<T>,
|
||||||
libc::memalign(align as libc::size_t, size as libc::size_t)
|
_phantom: marker::PhantomData<T>,
|
||||||
|
_dropper: marker::PhantomData<D>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized, D: Dealloc<T>> BoxLike<T, D> {
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn from_raw_unchecked(p: *mut T) -> Self {
|
||||||
|
BoxLike {
|
||||||
|
inner: ptr::NonNull::new_unchecked(p),
|
||||||
|
_phantom: marker::PhantomData,
|
||||||
|
_dropper: marker::PhantomData,
|
||||||
}
|
}
|
||||||
).cast()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
const fn dangling<T>() -> *mut T {
|
pub unsafe fn from_raw(p: *mut T) -> Option<Self> {
|
||||||
mem::align_of::<T>() as *mut T
|
if p.is_null() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Self::from_raw_unchecked(p))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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]
|
#[inline]
|
||||||
pub fn into_raw(self) -> *mut T {
|
pub fn into_raw(self) -> *mut T {
|
||||||
let p = self.0;
|
let p = self.inner.as_ptr();
|
||||||
mem::forget(self);
|
mem::forget(self);
|
||||||
p
|
p
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn as_ptr(&self) -> *const T {
|
|
||||||
self.0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
impl<T: ?Sized, D: Dealloc<T>> Drop for BoxLike<T, D> {
|
||||||
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]
|
#[inline]
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
let p = self.inner.as_ptr();
|
||||||
unsafe {
|
unsafe {
|
||||||
ptr::drop_in_place(self.0);
|
ptr::drop_in_place(p);
|
||||||
libc::free(self.0.cast());
|
D::dealloc(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: SafePtr + ?Sized> Deref for CBox<T> {
|
impl<T: ?Sized, D: Dealloc<T>> Deref for BoxLike<T, D> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn deref(&self) -> &T {
|
fn deref(&self) -> &T {
|
||||||
unsafe { &*T::safe_ptr(self.0) }
|
unsafe { self.inner.as_ref() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: SafePtr + ?Sized> DerefMut for CBox<T> {
|
impl<T: ?Sized, D: Dealloc<T>> DerefMut for BoxLike<T, D> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn deref_mut(&mut self) -> &mut T {
|
fn deref_mut(&mut self) -> &mut T {
|
||||||
unsafe { &mut *T::safe_ptr(self.0) }
|
unsafe { self.inner.as_mut() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: fmt::Debug + SafePtr + ?Sized> fmt::Debug for CBox<T> {
|
pub struct DeallocFree;
|
||||||
|
|
||||||
|
impl<T: ?Sized> Dealloc<T> for DeallocFree {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
unsafe fn dealloc(p: *mut T) {
|
||||||
fmt::Debug::fmt(&**self, f)
|
libc::free(p as _);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: fmt::Display + SafePtr + ?Sized> fmt::Display for CBox<T> {
|
pub type CBox<T> = BoxLike<T, DeallocFree>;
|
||||||
#[inline]
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
fmt::Display::fmt(&**self, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
34
safe_libc/src/errno.rs
Normal file
34
safe_libc/src/errno.rs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
use crate::string;
|
||||||
|
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[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(*__errno_location()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Errno {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let mut buf = [0u8; 1024];
|
||||||
|
let cstr = unsafe {
|
||||||
|
if libc::strerror_r(self.0, buf.as_mut_ptr().cast(), buf.len()) != 0 {
|
||||||
|
return Err(fmt::Error);
|
||||||
|
}
|
||||||
|
string::CStr::from_bytes_with_nul_unchecked(&buf)
|
||||||
|
};
|
||||||
|
match cstr.to_str() {
|
||||||
|
Err(_) => Err(fmt::Error),
|
||||||
|
Ok(s) => f.write_str(s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,17 +1,20 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
#![feature(extern_types)]
|
||||||
|
#![feature(slice_ptr_len)]
|
||||||
|
#![feature(ffi_const)]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
pub use libc::*;
|
pub use libc::*;
|
||||||
|
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
pub mod boxed;
|
pub mod boxed;
|
||||||
|
pub mod errno;
|
||||||
pub mod stdio;
|
pub mod stdio;
|
||||||
pub mod string;
|
pub mod string;
|
||||||
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
pub fn strndup(cs: *const libc::c_char, n: libc::size_t) -> *mut libc::c_char;
|
|
||||||
|
|
||||||
// pub static stdin: *mut libc::FILE;
|
// pub static stdin: *mut libc::FILE;
|
||||||
pub static stdout: *mut libc::FILE;
|
pub static stdout: *mut libc::FILE;
|
||||||
pub static stderr: *mut libc::FILE;
|
pub static stderr: *mut libc::FILE;
|
||||||
|
|
|
@ -1,47 +1,104 @@
|
||||||
use crate as libc;
|
use crate::{self as libc, errno, string};
|
||||||
use crate::string;
|
|
||||||
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
use core::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
pub struct OStream {
|
pub struct Error {
|
||||||
file: *mut libc::FILE
|
pub errno: errno::Errno,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Error> for fmt::Error {
|
||||||
|
fn from(_err: Error) -> fmt::Error {
|
||||||
|
fmt::Error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Result<T> = core::result::Result<T, Error>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn check_io(ok: bool) -> Result<()> {
|
||||||
|
if ok {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(Error {
|
||||||
|
errno: errno::errno(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BasicOStream(*mut libc::FILE);
|
||||||
|
|
||||||
|
unsafe impl Sync for BasicOStream {}
|
||||||
|
unsafe impl Send for BasicOStream {}
|
||||||
|
|
||||||
|
pub type Stdout = BasicOStream;
|
||||||
|
pub type Stderr = BasicOStream;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn stdout() -> Stdout {
|
||||||
|
BasicOStream(unsafe { libc::stdout })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn stdout() -> OStream {
|
pub fn stderr() -> Stderr {
|
||||||
OStream { file: libc::stdout }
|
BasicOStream(unsafe { libc::stderr })
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BasicOStream {
|
||||||
|
#[inline]
|
||||||
|
pub fn flush(&mut self) -> Result<()> {
|
||||||
|
check_io(unsafe { libc::fflush(self.0) } == 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn stderr() -> OStream {
|
pub fn write(&mut self, b: &[u8]) -> Result<()> {
|
||||||
OStream { file: libc::stderr }
|
check_io(unsafe { libc::fwrite(b.as_ptr().cast(), 1, b.len(), self.0) } == b.len())
|
||||||
}
|
|
||||||
|
|
||||||
impl OStream {
|
|
||||||
#[inline]
|
|
||||||
pub fn write(&mut self, b: &[u8]) {
|
|
||||||
unsafe {
|
|
||||||
libc::fwrite(
|
|
||||||
b.as_ptr().cast(),
|
|
||||||
1,
|
|
||||||
b.len(),
|
|
||||||
self.file,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn puts(&mut self, s: &string::CStr) {
|
pub fn puts(&mut self, s: &string::CStr) -> Result<()> {
|
||||||
unsafe {
|
check_io(unsafe { libc::fputs(s.as_ptr(), self.0) } != libc::EOF)
|
||||||
libc::fputs(s.as_ptr(), self.file);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Write for OStream {
|
impl fmt::Write for BasicOStream {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||||
self.write(s.as_bytes());
|
self.write(s.as_bytes())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct OStream(BasicOStream);
|
||||||
|
|
||||||
|
impl OStream {
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn from_raw(file: *mut libc::FILE) -> OStream {
|
||||||
|
OStream(BasicOStream(file))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for OStream {
|
||||||
|
#[inline]
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
libc::fclose((self.0).0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for OStream {
|
||||||
|
type Target = BasicOStream;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn deref(&self) -> &BasicOStream {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for OStream {
|
||||||
|
#[inline]
|
||||||
|
fn deref_mut(&mut self) -> &mut BasicOStream {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,40 +1,31 @@
|
||||||
use crate as libc;
|
use crate::{self as libc, boxed::CBox, util};
|
||||||
use crate::util;
|
|
||||||
use crate::boxed::CBox;
|
|
||||||
|
|
||||||
use core::slice;
|
use core::{mem, slice};
|
||||||
use core::ops::{Deref, DerefMut};
|
use core::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
//pub struct FromBytesWithNulError {}
|
//pub struct FromBytesWithNulError {}
|
||||||
|
|
||||||
pub struct CStr { inner: libc::c_char }
|
extern "C" {
|
||||||
|
type RawCStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct CStr(RawCStr);
|
||||||
|
|
||||||
impl CStr {
|
impl CStr {
|
||||||
#[inline]
|
|
||||||
pub unsafe fn from_ptr_unchecked<'a>(p: *const libc::c_char) -> &'a CStr {
|
|
||||||
&*p.cast()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn from_ptr<'a>(p: *const libc::c_char) -> &'a CStr {
|
pub unsafe fn from_ptr<'a>(p: *const libc::c_char) -> &'a CStr {
|
||||||
util::check_ptr(p, 1);
|
&*(p as *const CStr)
|
||||||
CStr::from_ptr_unchecked(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub unsafe fn from_mut_ptr_unchecked<'a>(p: *mut libc::c_char) -> &'a mut CStr {
|
|
||||||
&mut *p.cast()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn from_mut_ptr<'a>(p: *mut libc::c_char) -> &'a mut CStr {
|
pub unsafe fn from_mut_ptr<'a>(p: *mut libc::c_char) -> &'a mut CStr {
|
||||||
util::check_ptr(p, 1);
|
&mut *(p as *mut CStr)
|
||||||
CStr::from_mut_ptr_unchecked(p)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
|
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
|
// TODO
|
||||||
|
@ -43,33 +34,37 @@ impl CStr {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
unsafe { libc::strlen(self.as_ptr()) as usize }
|
unsafe { libc::strlen(self.as_ptr()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn as_ptr(&self) -> *const libc::c_char {
|
pub const fn as_ptr(&self) -> *const libc::c_char {
|
||||||
&self.inner
|
(self as *const CStr).cast()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_mut_ptr(&mut self) -> *mut libc::c_char {
|
pub fn as_mut_ptr(&mut self) -> *mut libc::c_char {
|
||||||
&mut self.inner
|
(self as *mut CStr).cast()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_bytes(&self) -> &[u8] {
|
pub fn to_bytes(&self) -> &[u8] {
|
||||||
unsafe { slice::from_raw_parts(
|
unsafe { slice::from_raw_parts(self.as_ptr().cast(), self.len()) }
|
||||||
self.as_ptr().cast(),
|
|
||||||
self.len(),
|
|
||||||
) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_mut_bytes(&mut self) -> &mut [u8] {
|
pub fn to_mut_bytes(&mut self) -> &mut [u8] {
|
||||||
unsafe { slice::from_raw_parts_mut(
|
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr().cast(), self.len()) }
|
||||||
self.as_mut_ptr().cast(),
|
}
|
||||||
self.len(),
|
|
||||||
) }
|
#[inline]
|
||||||
|
pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> {
|
||||||
|
core::str::from_utf8(self.to_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_mut_str(&mut self) -> Result<&mut str, core::str::Utf8Error> {
|
||||||
|
core::str::from_utf8_mut(self.to_mut_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -80,28 +75,28 @@ impl CStr {
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! cstr {
|
macro_rules! cstr {
|
||||||
($s:expr) => (
|
($s:expr) => {
|
||||||
unsafe { $crate::string::CStr::from_bytes_with_nul_unchecked(concat!($s, "\0").as_bytes()) }
|
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: CBox<CStr>,
|
||||||
|
}
|
||||||
|
|
||||||
impl CString {
|
impl CString {
|
||||||
#[inline]
|
|
||||||
pub unsafe fn from_raw_unchecked(p: *mut libc::c_char) -> CString {
|
|
||||||
CString { inner: CBox::from_raw_unchecked(p) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn from_raw(p: *mut libc::c_char) -> CString {
|
pub unsafe fn from_raw(p: *mut libc::c_char) -> CString {
|
||||||
util::check_ptr(p, 1);
|
CString {
|
||||||
CString::from_raw_unchecked(p)
|
inner: CBox::from_raw_unchecked(p as *mut CStr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn into_raw(self) -> *mut libc::c_char {
|
pub fn into_raw(mut self) -> *mut libc::c_char {
|
||||||
self.inner.into_raw()
|
let p = self.as_mut_ptr();
|
||||||
|
mem::forget(self);
|
||||||
|
p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,26 +105,24 @@ impl Deref for CString {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn deref(&self) -> &CStr {
|
fn deref(&self) -> &CStr {
|
||||||
unsafe { CStr::from_ptr(&*self.inner) }
|
&*self.inner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DerefMut for CString {
|
impl DerefMut for CString {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn deref_mut(&mut self) -> &mut CStr {
|
fn deref_mut(&mut self) -> &mut CStr {
|
||||||
unsafe { CStr::from_mut_ptr(&mut *self.inner) }
|
&mut *self.inner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&[u8]> for CString {
|
impl From<&[u8]> for CString {
|
||||||
fn from(s: &[u8]) -> CString {
|
fn from(s: &[u8]) -> CString {
|
||||||
unsafe {
|
unsafe {
|
||||||
CString::from_raw_unchecked(
|
CString::from_raw(util::must_succeed(libc::strndup(
|
||||||
util::must_succeed(libc::strndup(
|
|
||||||
s.as_ptr().cast(),
|
s.as_ptr().cast(),
|
||||||
s.len() as libc::size_t,
|
s.len(),
|
||||||
))
|
)))
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,8 +137,6 @@ impl From<&str> for CString {
|
||||||
impl From<&CStr> for CString {
|
impl From<&CStr> for CString {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(s: &CStr) -> CString {
|
fn from(s: &CStr) -> CString {
|
||||||
unsafe {
|
unsafe { CString::from_raw(util::must_succeed(libc::strdup(s.as_ptr()))) }
|
||||||
CString::from_raw_unchecked(util::must_succeed(libc::strdup(s.as_ptr())))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,9 @@
|
||||||
use core::mem;
|
use alloc::alloc;
|
||||||
|
|
||||||
#[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]
|
#[inline]
|
||||||
pub fn must_succeed<T>(p: *mut T) -> *mut T {
|
pub fn must_succeed<T>(p: *mut T) -> *mut T {
|
||||||
assert!(!p.is_null(), "allocation failure");
|
if p.is_null() {
|
||||||
|
alloc::handle_alloc_error(alloc::Layout::new::<T>())
|
||||||
|
}
|
||||||
p
|
p
|
||||||
}
|
}
|
||||||
|
|
30
src/main.rs
30
src/main.rs
|
@ -1,39 +1,53 @@
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
#![feature(alloc_error_handler)]
|
||||||
|
|
||||||
use safe_libc as libc;
|
mod system_alloc;
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
use libc::cstr;
|
use libc::cstr;
|
||||||
|
use safe_libc as libc;
|
||||||
|
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn main(_nargs: libc::c_int, _args: *const *const libc::c_char) -> libc::c_int {
|
pub extern "C" fn main(_nargs: libc::c_int, _args: *const *const libc::c_char) -> libc::c_int {
|
||||||
let mut stdout = unsafe { libc::stdio::stdout() };
|
let mut stdout = libc::stdio::stdout();
|
||||||
|
|
||||||
{
|
{
|
||||||
let foo = cstr!("Foo!\n");
|
let foo = cstr!("Foo!\n");
|
||||||
stdout.puts(foo);
|
let _ = stdout.puts(foo);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let x = libc::string::CString::from("foo");
|
let x = libc::string::CString::from("foo");
|
||||||
let l = x.len();
|
let l = x.len();
|
||||||
let y = x.into_raw();
|
let y = x.into_raw();
|
||||||
let z = unsafe {
|
let z = unsafe { alloc::boxed::Box::from_raw(core::ptr::slice_from_raw_parts_mut(y, l)) };
|
||||||
libc::boxed::CBox::slice_from_raw_parts(y, l)
|
|
||||||
};
|
|
||||||
let _ = writeln!(stdout, "Foo: {} {} {}", z[0], z[1], z[2]);
|
let _ = writeln!(stdout, "Foo: {} {} {}", z[0], z[1], z[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let b = libc::boxed::CBox::new(42);
|
let x = libc::string::CString::from("bar");
|
||||||
|
let _ = stdout.puts(&x);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let b = alloc::boxed::Box::new(42);
|
||||||
let _ = writeln!(stdout, "Bar: {}", b);
|
let _ = writeln!(stdout, "Bar: {}", b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let x = alloc::boxed::Box::new(());
|
||||||
|
let _ = writeln!(stdout, "Box: {:?}", x);
|
||||||
|
}
|
||||||
|
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
let _ = writeln!(unsafe { libc::stdio::stderr() }, "Panic: {}", info);
|
let _ = writeln!(libc::stdio::stderr(), "Panic: {}", info);
|
||||||
unsafe { libc::abort() }
|
unsafe { libc::abort() }
|
||||||
}
|
}
|
||||||
|
|
22
src/system_alloc.rs
Normal file
22
src/system_alloc.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
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;
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
|
#[alloc_error_handler]
|
||||||
|
fn alloc_error(_: core::alloc::Layout) -> ! {
|
||||||
|
panic!("allocation failure");
|
||||||
|
}
|
Reference in a new issue