summaryrefslogtreecommitdiffstats
path: root/safe_libc/src
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2020-04-13 02:13:58 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2020-04-13 02:13:58 +0200
commit5b449f4e1e43bc59109da5a37edf5ec911d3df8e (patch)
tree46968e5619a1088f131f532a5d78e8ff4d033325 /safe_libc/src
parentfff906a78ba545e77d087a82711b30bcc8e0d0c5 (diff)
downloadneco-5b449f4e1e43bc59109da5a37edf5ec911d3df8e.tar
neco-5b449f4e1e43bc59109da5a37edf5ec911d3df8e.zip
IO, error handling
Diffstat (limited to 'safe_libc/src')
-rw-r--r--safe_libc/src/boxed.rs2
-rw-r--r--safe_libc/src/errno.rs29
-rw-r--r--safe_libc/src/lib.rs1
-rw-r--r--safe_libc/src/stdio.rs102
-rw-r--r--safe_libc/src/string.rs23
5 files changed, 130 insertions, 27 deletions
diff --git a/safe_libc/src/boxed.rs b/safe_libc/src/boxed.rs
index fa3e45d..4a38b70 100644
--- a/safe_libc/src/boxed.rs
+++ b/safe_libc/src/boxed.rs
@@ -11,7 +11,7 @@ fn alloc<T>(len: usize) -> *mut T {
let align = mem::align_of::<T>();
util::must_succeed(
unsafe {
- libc::memalign(align as libc::size_t, size as libc::size_t)
+ libc::memalign(align, size)
}
).cast()
}
diff --git a/safe_libc/src/errno.rs b/safe_libc/src/errno.rs
new file mode 100644
index 0000000..be944d1
--- /dev/null
+++ b/safe_libc/src/errno.rs
@@ -0,0 +1,29 @@
+use crate::string;
+
+use core::fmt;
+
+#[derive(Clone, Copy, Debug)]
+#[repr(transparent)]
+pub struct Errno(pub libc::c_int);
+
+#[inline]
+pub fn errno() -> Errno {
+ unsafe { Errno(*libc::__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),
+ }
+ }
+}
diff --git a/safe_libc/src/lib.rs b/safe_libc/src/lib.rs
index 0ab0e89..aec5acc 100644
--- a/safe_libc/src/lib.rs
+++ b/safe_libc/src/lib.rs
@@ -5,6 +5,7 @@ pub use libc::*;
mod util;
pub mod boxed;
+pub mod errno;
pub mod stdio;
pub mod string;
diff --git a/safe_libc/src/stdio.rs b/safe_libc/src/stdio.rs
index 271f023..2d19725 100644
--- a/safe_libc/src/stdio.rs
+++ b/safe_libc/src/stdio.rs
@@ -1,47 +1,111 @@
-use crate as libc;
-use crate::string;
+use crate::{self as libc, errno, string};
use core::fmt;
+use core::ops::{Deref, DerefMut};
-pub struct OStream {
- file: *mut libc::FILE
+pub struct Error {
+ pub errno: errno::Errno,
}
+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 unsafe fn stdout() -> OStream {
- OStream { file: libc::stdout }
+pub fn stdout() -> Stdout {
+ BasicOStream(unsafe { libc::stdout })
}
#[inline]
-pub unsafe fn stderr() -> OStream {
- OStream { file: libc::stderr }
+pub fn stderr() -> Stderr {
+ BasicOStream(unsafe { libc::stderr })
}
-impl OStream {
+impl BasicOStream {
#[inline]
- pub fn write(&mut self, b: &[u8]) {
- unsafe {
+ pub fn flush(&mut self) -> Result<()> {
+ 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.file,
- );
+ 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)
+ }
+}
+
+impl fmt::Write for BasicOStream {
+ #[inline]
+ fn write_str(&mut self, s: &str) -> fmt::Result {
+ if self.write(s.as_bytes()).is_err() {
+ return Err(fmt::Error);
}
+ 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]
- pub fn puts(&mut self, s: &string::CStr) {
+ fn drop(&mut self) {
unsafe {
- libc::fputs(s.as_ptr(), self.file);
+ libc::fclose((self.0).0);
}
}
}
-impl fmt::Write for OStream {
+impl Deref for OStream {
+ type Target = BasicOStream;
+
#[inline]
- fn write_str(&mut self, s: &str) -> fmt::Result {
- self.write(s.as_bytes());
- Ok(())
+ fn deref(&self) -> &BasicOStream {
+ &self.0
+ }
+}
+
+impl DerefMut for OStream {
+ #[inline]
+ fn deref_mut(&mut self) -> &mut BasicOStream {
+ &mut self.0
}
}
diff --git a/safe_libc/src/string.rs b/safe_libc/src/string.rs
index 8f973ad..53f8f87 100644
--- a/safe_libc/src/string.rs
+++ b/safe_libc/src/string.rs
@@ -1,12 +1,11 @@
-use crate as libc;
-use crate::util;
-use crate::boxed::CBox;
+use crate::{self as libc, util, boxed::CBox};
use core::slice;
use core::ops::{Deref, DerefMut};
//pub struct FromBytesWithNulError {}
+#[repr(transparent)]
pub struct CStr { inner: libc::c_char }
impl CStr {
@@ -43,7 +42,7 @@ impl CStr {
#[inline]
pub fn len(&self) -> usize {
- unsafe { libc::strlen(self.as_ptr()) as usize }
+ unsafe { libc::strlen(self.as_ptr()) }
}
#[inline]
@@ -57,7 +56,7 @@ impl CStr {
}
#[inline]
- pub fn as_bytes(&self) -> &[u8] {
+ pub fn to_bytes(&self) -> &[u8] {
unsafe { slice::from_raw_parts(
self.as_ptr().cast(),
self.len(),
@@ -65,7 +64,7 @@ impl CStr {
}
#[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(
self.as_mut_ptr().cast(),
self.len(),
@@ -73,6 +72,16 @@ impl CStr {
}
#[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]
pub fn to_owned(self: &CStr) -> CString {
CString::from(self)
}
@@ -127,7 +136,7 @@ impl From<&[u8]> for CString {
CString::from_raw_unchecked(
util::must_succeed(libc::strndup(
s.as_ptr().cast(),
- s.len() as libc::size_t,
+ s.len(),
))
)
}