summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2020-04-04 13:22:18 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2020-04-04 14:23:00 +0200
commitf0b3d5166ef1255fac880b146875ef46d2599a13 (patch)
tree61c993cf32dedc1172bcf40cd5207e05a3b032a9
parent52b498494534784c77bfa4a93706be40620ebd9a (diff)
downloadneco-f0b3d5166ef1255fac880b146875ef46d2599a13.tar
neco-f0b3d5166ef1255fac880b146875ef46d2599a13.zip
Reorganize
-rw-r--r--.gitignore4
-rw-r--r--Cargo.lock7
-rw-r--r--Cargo.toml2
-rw-r--r--safe_libc/Cargo.lock14
-rw-r--r--safe_libc/Cargo.toml10
-rw-r--r--safe_libc/src/boxed.rs146
-rw-r--r--safe_libc/src/lib.rs (renamed from src/c/posix.rs)11
-rw-r--r--safe_libc/src/stdio.rs (renamed from src/c/stdio.rs)15
-rw-r--r--safe_libc/src/string.rs151
-rw-r--r--safe_libc/src/util.rs18
-rw-r--r--src/c/mod.rs3
-rw-r--r--src/c/string.rs266
-rw-r--r--src/main.rs17
13 files changed, 378 insertions, 286 deletions
diff --git a/.gitignore b/.gitignore
index f0e3bca..11d7baa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,2 @@
-/target
-**/*.rs.bk \ No newline at end of file
+target
+*.rs.bk
diff --git a/Cargo.lock b/Cargo.lock
index 7495526..45e6ba1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -10,5 +10,12 @@ checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0"
name = "neco"
version = "0.1.0"
dependencies = [
+ "safe_libc",
+]
+
+[[package]]
+name = "safe_libc"
+version = "0.1.0"
+dependencies = [
"libc",
]
diff --git a/Cargo.toml b/Cargo.toml
index 4f8be4f..b7770a0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,7 +5,7 @@ authors = ["Matthias Schiffer <mschiffer@universe-factory.net>"]
edition = "2018"
[dependencies]
-libc = { version = "0.2.68", default-features = false }
+safe_libc = { path = "safe_libc" }
[profile.dev]
panic = "abort"
diff --git a/safe_libc/Cargo.lock b/safe_libc/Cargo.lock
new file mode 100644
index 0000000..e659af2
--- /dev/null
+++ b/safe_libc/Cargo.lock
@@ -0,0 +1,14 @@
+# 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",
+]
diff --git a/safe_libc/Cargo.toml b/safe_libc/Cargo.toml
new file mode 100644
index 0000000..f776d09
--- /dev/null
+++ b/safe_libc/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "safe_libc"
+version = "0.1.0"
+authors = ["Matthias Schiffer <mschiffer@universe-factory.net>"]
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+libc = { version = "0.2.68", default-features = false }
diff --git a/safe_libc/src/boxed.rs b/safe_libc/src/boxed.rs
new file mode 100644
index 0000000..72c961c
--- /dev/null
+++ b/safe_libc/src/boxed.rs
@@ -0,0 +1,146 @@
+use crate::util;
+
+use core::{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 as libc::size_t, size as libc::size_t) as *mut T
+ }
+ )
+}
+
+#[inline]
+fn dangling<T>() -> *mut T {
+ mem::align_of::<T>() as *mut T
+}
+
+#[inline]
+fn slice_len<T>(p: *const [T]) -> usize {
+ unsafe { mem::transmute::<*const [T], [usize; 2]>(p)[1] }
+}
+
+pub struct CBox<T: ?Sized>(*mut T);
+
+impl<T: ?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)
+ }
+
+ #[inline]
+ fn safe_ptr(&self) -> *mut T {
+ if util::zst::<T>(1) {
+ return dangling();
+ }
+
+ debug_assert!(!self.0.is_null(), "NULL ptr");
+ self.0
+ }
+}
+
+impl<T> CBox<[T]> {
+ #[inline]
+ fn safe_ptr(&self) -> *mut [T] {
+ if self.0.is_null() {
+ let len = slice_len(self.0);
+ debug_assert!(util::zst::<T>(len), "NULL ptr");
+ return ptr::slice_from_raw_parts_mut(dangling(), len);
+ }
+
+ self.0
+ }
+}
+
+impl<T: ?Sized> Drop for CBox<T> {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ ptr::drop_in_place(self.0);
+ libc::free(self.0 as *mut libc::c_void);
+ }
+ }
+}
+
+impl<T> Deref for CBox<T> {
+ type Target = T;
+
+ #[inline]
+ fn deref(&self) -> &T {
+ unsafe { &*self.safe_ptr() }
+ }
+}
+
+impl<T> DerefMut for CBox<T> {
+ #[inline]
+ fn deref_mut(&mut self) -> &mut T {
+ unsafe { &mut *self.safe_ptr() }
+ }
+}
+
+impl<T> Deref for CBox<[T]> {
+ type Target = [T];
+
+ #[inline]
+ fn deref(&self) -> &[T] {
+ unsafe { &*self.safe_ptr() }
+ }
+}
+
+impl<T> DerefMut for CBox<[T]> {
+ #[inline]
+ fn deref_mut(&mut self) -> &mut [T] {
+ unsafe { &mut *self.safe_ptr() }
+ }
+}
diff --git a/src/c/posix.rs b/safe_libc/src/lib.rs
index 6b63ea7..0ab0e89 100644
--- a/src/c/posix.rs
+++ b/safe_libc/src/lib.rs
@@ -1,3 +1,14 @@
+#![no_std]
+
+pub use libc::*;
+
+mod util;
+
+pub mod boxed;
+pub mod stdio;
+pub mod string;
+
+
extern "C" {
pub fn strndup(cs: *const libc::c_char, n: libc::size_t) -> *mut libc::c_char;
diff --git a/src/c/stdio.rs b/safe_libc/src/stdio.rs
index c878f19..5f33f74 100644
--- a/src/c/stdio.rs
+++ b/safe_libc/src/stdio.rs
@@ -1,21 +1,24 @@
-use core::fmt;
+use crate as libc;
+use crate::string;
-use super::posix;
-use super::string;
+use core::fmt;
pub struct OStream {
file: *mut libc::FILE
}
+#[inline]
pub unsafe fn stdout() -> OStream {
- OStream { file: posix::stdout }
+ OStream { file: libc::stdout }
}
+#[inline]
pub unsafe fn stderr() -> OStream {
- OStream { file: posix::stderr }
+ OStream { file: libc::stderr }
}
impl OStream {
+ #[inline]
pub fn write(&mut self, b: &[u8]) {
unsafe {
libc::fwrite(
@@ -27,6 +30,7 @@ impl OStream {
}
}
+ #[inline]
pub fn puts(&mut self, s: &string::CStr) {
unsafe {
libc::fputs(s.as_ptr(), self.file);
@@ -35,6 +39,7 @@ impl OStream {
}
impl fmt::Write for OStream {
+ #[inline]
fn write_str(&mut self, s: &str) -> fmt::Result {
self.write(s.as_bytes());
Ok(())
diff --git a/safe_libc/src/string.rs b/safe_libc/src/string.rs
new file mode 100644
index 0000000..c85f788
--- /dev/null
+++ b/safe_libc/src/string.rs
@@ -0,0 +1,151 @@
+use crate as libc;
+use crate::util;
+use crate::boxed::CBox;
+
+use core::slice;
+use core::ops::{Deref, DerefMut};
+
+//pub struct FromBytesWithNulError {}
+
+pub struct CStr { inner: libc::c_char }
+
+impl CStr {
+ #[inline]
+ pub unsafe fn from_ptr_unchecked<'a>(p: *const libc::c_char) -> &'a CStr {
+ &*(p as *const CStr)
+ }
+
+ #[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 {
+ &mut *(p as *mut CStr)
+ }
+
+ #[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() as *const libc::c_char)
+ }
+
+ // TODO
+ //pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&CStr, FromBytesWithNulError> {
+ //}
+
+ #[inline]
+ pub fn len(&self) -> usize {
+ unsafe { libc::strlen(self.as_ptr()) as usize }
+ }
+
+ #[inline]
+ pub const fn as_ptr(&self) -> *const libc::c_char {
+ &self.inner
+ }
+
+ #[inline]
+ pub fn as_mut_ptr(&mut self) -> *mut libc::c_char {
+ &mut self.inner
+ }
+
+ #[inline]
+ pub fn as_bytes(&self) -> &[u8] {
+ unsafe { slice::from_raw_parts(
+ self.as_ptr() as *const u8,
+ self.len(),
+ ) }
+ }
+
+ #[inline]
+ pub fn as_mut_bytes(&mut self) -> &mut [u8] {
+ unsafe { slice::from_raw_parts_mut(
+ self.as_mut_ptr() as *mut u8,
+ self.len(),
+ ) }
+ }
+
+ #[inline]
+ pub fn to_owned(self: &CStr) -> CString {
+ CString::from(self)
+ }
+}
+
+#[macro_export]
+macro_rules! cstr {
+ ($s:expr) => (
+ unsafe { $crate::string::CStr::from_bytes_with_nul_unchecked(concat!($s, "\0").as_bytes()) }
+ )
+}
+
+pub struct CString { inner: CBox<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)
+ }
+
+ #[inline]
+ pub fn into_raw(self) -> *mut libc::c_char {
+ self.inner.into_raw()
+ }
+}
+
+impl Deref for CString {
+ type Target = CStr;
+
+ #[inline]
+ fn deref(&self) -> &CStr {
+ unsafe { CStr::from_ptr(&*self.inner) }
+ }
+}
+
+impl DerefMut for CString {
+ #[inline]
+ fn deref_mut(&mut self) -> &mut CStr {
+ unsafe { CStr::from_mut_ptr(&mut *self.inner) }
+ }
+}
+
+impl From<&[u8]> for CString {
+ fn from(s: &[u8]) -> CString {
+ unsafe {
+ CString::from_raw_unchecked(
+ util::must_succeed(libc::strndup(
+ s.as_ptr() as *const libc::c_char,
+ s.len() as libc::size_t,
+ ))
+ )
+ }
+ }
+}
+
+impl From<&str> for CString {
+ #[inline]
+ fn from(s: &str) -> CString {
+ CString::from(s.as_bytes())
+ }
+}
+
+impl From<&CStr> for CString {
+ #[inline]
+ fn from(s: &CStr) -> CString {
+ unsafe {
+ CString::from_raw_unchecked(util::must_succeed(libc::strdup(s.as_ptr())))
+ }
+ }
+}
diff --git a/safe_libc/src/util.rs b/safe_libc/src/util.rs
new file mode 100644
index 0000000..b8a4ed5
--- /dev/null
+++ b/safe_libc/src/util.rs
@@ -0,0 +1,18 @@
+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");
+ p
+}
diff --git a/src/c/mod.rs b/src/c/mod.rs
deleted file mode 100644
index 3694561..0000000
--- a/src/c/mod.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-pub mod posix;
-pub mod stdio;
-pub mod string;
diff --git a/src/c/string.rs b/src/c/string.rs
deleted file mode 100644
index 3d991dc..0000000
--- a/src/c/string.rs
+++ /dev/null
@@ -1,266 +0,0 @@
-use super::posix;
-use core::{mem, ptr, slice};
-use core::ops::{Deref, DerefMut};
-
-fn must_succeed<T>(p: *mut T) -> *mut T {
- assert!(!p.is_null(), "allocation failure");
- p
-}
-
-fn zst<T>(count: usize) -> bool {
- mem::size_of::<T>() == 0 || count == 0
-}
-
-fn alloc<T>(count: usize) -> *mut T {
- if zst::<T>(count) {
- return ptr::null_mut();
- }
- let size = count * mem::size_of::<T>();
- let align = mem::align_of::<T>();
- must_succeed(
- unsafe {
- libc::memalign(align as libc::size_t, size as libc::size_t) as *mut T
- }
- )
-}
-
-fn dangling<T>() -> *mut T {
- mem::align_of::<T>() as *mut T
-}
-
-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");
-}
-
-fn slice_len<T>(p: *const [T]) -> usize {
- unsafe { mem::transmute::<*const [T], [usize; 2]>(p)[1] }
-}
-
-pub struct CBox<T: ?Sized>(*mut T);
-
-impl<T: ?Sized> CBox<T> {
- pub unsafe fn from_raw_unchecked(p: *mut T) -> CBox<T> {
- CBox(p)
- }
-
- pub fn into_raw(self) -> *mut T {
- let p = self.0;
- mem::forget(self);
- p
- }
-
- pub fn as_ptr(&self) -> *const T {
- self.0
- }
-
- pub fn as_mut_ptr(&mut self) -> *mut T {
- self.0
- }
-}
-
-impl<T> CBox<T> {
- pub fn new(value: T) -> CBox<T> {
- let p = alloc(1);
- unsafe {
- ptr::write(p, value);
- CBox::from_raw_unchecked(p)
- }
- }
-
- pub unsafe fn from_raw(p: *mut T) -> CBox<T> {
- check_ptr(p, 1);
- CBox(p)
- }
-
- pub unsafe fn slice_from_raw_parts_unchecked(p: *mut T, len: usize) -> CBox<[T]> {
- CBox(ptr::slice_from_raw_parts_mut(p, len))
- }
-
- pub unsafe fn slice_from_raw_parts(p: *mut T, len: usize) -> CBox<[T]> {
- check_ptr(p, len);
- CBox::slice_from_raw_parts_unchecked(p, len)
- }
-
- fn safe_ptr(&self) -> *mut T {
- if self.0.is_null() {
- debug_assert!(zst::<T>(1), "NULL ptr");
- return dangling();
- }
-
- self.0
- }
-}
-
-impl<T> CBox<[T]> {
- fn safe_ptr(&self) -> *mut [T] {
- if self.0.is_null() {
- let len = slice_len(self.0);
- debug_assert!(zst::<T>(len), "NULL ptr");
- return ptr::slice_from_raw_parts_mut(dangling(), len);
- }
-
- self.0
- }
-}
-
-impl<T: ?Sized> Drop for CBox<T> {
- fn drop(&mut self) {
- unsafe {
- ptr::drop_in_place(self.0);
- libc::free(self.0 as *mut libc::c_void);
- }
- }
-}
-
-impl<T> Deref for CBox<T> {
- type Target = T;
-
- fn deref(&self) -> &T {
- unsafe { &*self.safe_ptr() }
- }
-}
-
-impl<T> DerefMut for CBox<T> {
- fn deref_mut(&mut self) -> &mut T {
- unsafe { &mut *self.safe_ptr() }
- }
-}
-
-impl<T> Deref for CBox<[T]> {
- type Target = [T];
-
- fn deref(&self) -> &[T] {
- unsafe { &*self.safe_ptr() }
- }
-}
-
-impl<T> DerefMut for CBox<[T]> {
- fn deref_mut(&mut self) -> &mut [T] {
- unsafe { &mut *self.safe_ptr() }
- }
-}
-
-//pub struct FromBytesWithNulError {}
-
-pub struct CStr { inner: libc::c_char }
-
-impl CStr {
- pub unsafe fn from_ptr_unchecked<'a>(p: *const libc::c_char) -> &'a CStr {
- &*(p as *const CStr)
- }
-
- pub unsafe fn from_ptr<'a>(p: *const libc::c_char) -> &'a CStr {
- check_ptr(p, 1);
- CStr::from_ptr_unchecked(p)
- }
-
- pub unsafe fn from_mut_ptr_unchecked<'a>(p: *mut libc::c_char) -> &'a mut CStr {
- &mut *(p as *mut CStr)
- }
-
- pub unsafe fn from_mut_ptr<'a>(p: *mut libc::c_char) -> &'a mut CStr {
- check_ptr(p, 1);
- CStr::from_mut_ptr_unchecked(p)
- }
-
- pub unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
- CStr::from_ptr_unchecked(bytes.as_ptr() as *const libc::c_char)
- }
-
- // TODO
- //pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&CStr, FromBytesWithNulError> {
- //}
-
- pub fn len(&self) -> usize {
- unsafe { libc::strlen(self.as_ptr()) as usize }
- }
-
- pub const fn as_ptr(&self) -> *const libc::c_char {
- &self.inner
- }
-
- pub fn as_mut_ptr(&mut self) -> *mut libc::c_char {
- &mut self.inner
- }
-
- pub fn as_bytes(&self) -> &[u8] {
- unsafe { slice::from_raw_parts(
- self.as_ptr() as *const u8,
- self.len(),
- ) }
- }
-
- pub fn as_mut_bytes(&mut self) -> &mut [u8] {
- unsafe { slice::from_raw_parts_mut(
- self.as_mut_ptr() as *mut u8,
- self.len(),
- ) }
- }
-
- pub fn to_owned(self: &CStr) -> CString {
- CString::from(self)
- }
-}
-
-#[macro_export]
-macro_rules! cstr {
- ($s:expr) => (
- unsafe { $crate::c::string::CStr::from_bytes_with_nul_unchecked(concat!($s, "\0").as_bytes()) }
- )
-}
-
-pub struct CString { inner: CBox<libc::c_char> }
-
-impl CString {
- pub unsafe fn from_raw_unchecked(p: *mut libc::c_char) -> CString {
- CString { inner: CBox::from_raw_unchecked(p) }
- }
-
- pub unsafe fn from_raw(p: *mut libc::c_char) -> CString {
- CString { inner: CBox::from_raw(p) }
- }
-
- pub fn into_raw(self) -> *mut libc::c_char {
- self.inner.into_raw()
- }
-}
-
-impl Deref for CString {
- type Target = CStr;
-
- fn deref(&self) -> &CStr {
- unsafe { CStr::from_ptr(&*self.inner) }
- }
-}
-
-impl DerefMut for CString {
- fn deref_mut(&mut self) -> &mut CStr {
- unsafe { CStr::from_mut_ptr(&mut *self.inner) }
- }
-}
-
-impl From<&[u8]> for CString {
- fn from(s: &[u8]) -> CString {
- unsafe {
- CString::from_raw_unchecked(must_succeed(posix::strndup(
- s.as_ptr() as *const libc::c_char,
- s.len() as libc::size_t,
- )))
- }
- }
-}
-
-impl From<&str> for CString {
- fn from(s: &str) -> CString {
- CString::from(s.as_bytes())
- }
-}
-
-impl From<&CStr> for CString {
- fn from(s: &CStr) -> CString {
- unsafe {
- CString::from_raw_unchecked(must_succeed(libc::strdup(s.as_ptr())))
- }
- }
-}
diff --git a/src/main.rs b/src/main.rs
index 5f86a61..67d8baa 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,30 +1,29 @@
#![no_main]
#![no_std]
-extern crate libc;
-
-mod c;
+use safe_libc as libc;
+use libc::cstr;
use core::fmt::Write;
#[no_mangle]
pub extern "C" fn main(_nargs: libc::c_int, _args: *const *const libc::c_char) -> libc::c_int {
- let mut stdout = unsafe { c::stdio::stdout() };
- let x = c::string::CString::from("foo");
+ let mut stdout = unsafe { libc::stdio::stdout() };
+ let x = libc::string::CString::from("foo");
let l = x.len();
let y = x.into_raw();
let z = unsafe {
- c::string::CBox::slice_from_raw_parts(y, l)
+ libc::boxed::CBox::slice_from_raw_parts(y, l)
};
//let y = unsafe { c::string::CBox::from_raw(x) };
- //let foo = cstr!("Foo! %p\n");
- //c::stdio::stdout().puts(foo);
+ let foo = cstr!("Foo!\n");
+ stdout.puts(foo);
let _ = writeln!(stdout, "Foo: {} {} {}", z[0], z[1], z[2]);
0
}
#[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! {
- let _ = writeln!(unsafe { c::stdio::stderr() }, "Panic: {}", info);
+ let _ = writeln!(unsafe { libc::stdio::stderr() }, "Panic: {}", info);
unsafe { libc::abort() }
}