Skip to content

Commit 30f3c26

Browse files
committed
Basic I/O functions done
0 parents  commit 30f3c26

File tree

6 files changed

+260
-0
lines changed

6 files changed

+260
-0
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/target
2+
Cargo.lock
3+
.idea

Cargo.toml

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[package]
2+
name = "pipelib"
3+
version = "0.1.0"
4+
edition = "2018"
5+
authors = ["Keating K. Reid <[email protected]>"]
6+
description = "A thin wrapper over Unix pipes with polling functionality."
7+
license = "LGPL-2.1"
8+
9+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
10+
11+
[dependencies]
12+
libc = "0.2.98"

src/lib.rs

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#![allow(unused)]
2+
mod pipe;
3+
mod reader;
4+
mod writer;
5+
6+
use crate::{pipe::Pipe, reader::Reader, writer::Writer};
7+
use libc::c_int;
8+
9+
pub(crate) mod crate_macros {
10+
#[macro_export]
11+
macro_rules! oserr {
12+
() => {
13+
std::io::Error::last_os_error()
14+
};
15+
}
16+
17+
#[macro_export]
18+
macro_rules! assert_ok {
19+
($val:ident) => {
20+
assert!($val.is_ok(), "{:?}", $val.unwrap_err())
21+
};
22+
($e:expr) => {
23+
let tmp = $e;
24+
assert_ok!(tmp)
25+
};
26+
}
27+
}
28+
29+
pub fn new() -> std::io::Result<(Reader, Writer)> {
30+
let mut fds: [c_int; 2] = [-1, -1];
31+
unsafe {
32+
if libc::pipe(fds.as_mut_ptr()) != 0 {
33+
return Err(oserr!());
34+
}
35+
for fd in fds {
36+
if libc::fcntl(fd, libc::FD_CLOEXEC) != 0
37+
|| libc::fcntl(fd, libc::F_SETFL, libc::O_NONBLOCK) != 0
38+
{
39+
return Err(oserr!());
40+
}
41+
}
42+
}
43+
debug_assert_ne!(fds[0], -1);
44+
debug_assert_ne!(fds[1], -1);
45+
Ok((Reader::new(fds[0]), Writer::new(fds[1])))
46+
}

src/pipe.rs

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
use crate::oserr;
2+
use libc::{self, c_int, c_void, size_t};
3+
use std::{
4+
io::{self, prelude::*},
5+
mem,
6+
os::unix::io::{FromRawFd, IntoRawFd, RawFd},
7+
};
8+
9+
#[derive(Debug)]
10+
pub(crate) struct Pipe(pub(crate) c_int);
11+
12+
impl Pipe {
13+
fn write_from_ptr(&mut self, buf: *const c_void, len: usize) -> io::Result<usize> {
14+
let written = unsafe { libc::write(self.0, buf, len) };
15+
if written < 0 {
16+
Err(oserr!())
17+
} else {
18+
Ok(written as usize)
19+
}
20+
}
21+
22+
fn read_to_ptr(&self, buf: *mut c_void, len: usize) -> io::Result<usize> {
23+
let bytes_read = unsafe { libc::read(self.0, buf, len as size_t) };
24+
if bytes_read < 0 {
25+
let e = oserr!();
26+
match e.kind() {
27+
io::ErrorKind::WouldBlock => Ok(0),
28+
_ => return Err(e),
29+
}
30+
} else {
31+
Ok(bytes_read as usize)
32+
}
33+
}
34+
}
35+
36+
impl Write for Pipe {
37+
#[inline]
38+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
39+
let ptr = buf.as_ptr() as *const c_void;
40+
self.write_from_ptr(ptr, buf.len())
41+
}
42+
43+
fn write_all(&mut self, mut buf: &[u8]) -> io::Result<()> {
44+
let mut to_write = buf.len();
45+
let mut ptr = buf.as_ptr() as *const c_void;
46+
while to_write > 0 {
47+
let written = self.write_from_ptr(ptr, to_write)?;
48+
to_write -= written;
49+
unsafe { ptr.add(written) };
50+
}
51+
Ok(())
52+
}
53+
54+
#[inline]
55+
fn flush(&mut self) -> io::Result<()> {
56+
Ok(())
57+
}
58+
}
59+
60+
impl Read for Pipe {
61+
#[inline]
62+
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
63+
let ptr = buf.as_mut_ptr() as *mut c_void;
64+
self.read_to_ptr(ptr, buf.len())
65+
}
66+
}
67+
68+
impl FromRawFd for Pipe {
69+
#[inline]
70+
unsafe fn from_raw_fd(fd: RawFd) -> Self {
71+
Pipe(fd)
72+
}
73+
}
74+
75+
impl IntoRawFd for Pipe {
76+
#[inline]
77+
fn into_raw_fd(self) -> RawFd {
78+
self.0
79+
}
80+
}
81+
82+
#[cfg(test)]
83+
mod tests {
84+
use super::*;
85+
use crate::assert_ok;
86+
use std::io::prelude::*;
87+
88+
#[test]
89+
fn test_new() {
90+
assert_ok!(crate::new());
91+
}
92+
93+
#[test]
94+
fn test_read_write() {
95+
let test_msg = *b"Hello, world";
96+
let mut buf: [u8; 12] = [0; 12];
97+
let (mut reader, mut writer) = crate::new().unwrap();
98+
assert_ok!(writer.write(&test_msg));
99+
assert_ok!(reader.read(&mut buf));
100+
assert_eq!(test_msg, buf);
101+
}
102+
103+
#[test]
104+
fn test_read_to_end() {
105+
let test_msg = b"Hello, world".to_vec();
106+
let mut buf: Vec<u8> = Vec::with_capacity(6);
107+
let (mut reader, mut writer) = crate::new().unwrap();
108+
assert_ok!(writer.write(&test_msg));
109+
let res = reader.read_to_end(&mut buf);
110+
assert_ok!(res);
111+
let bytes_read = res.unwrap();
112+
assert_eq!(bytes_read, test_msg.len());
113+
assert_eq!(buf, test_msg);
114+
}
115+
}

src/reader.rs

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
use libc::c_int;
2+
3+
use crate::pipe::Pipe;
4+
use std::{
5+
io::{self, prelude::*},
6+
os::unix::io::{FromRawFd, IntoRawFd, RawFd},
7+
};
8+
9+
#[derive(Debug)]
10+
pub struct Reader(Pipe);
11+
12+
impl Reader {
13+
pub(crate) fn new(n: c_int) -> Reader {
14+
Reader(Pipe(n))
15+
}
16+
}
17+
18+
impl Read for Reader {
19+
#[inline]
20+
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
21+
self.0.read(buf)
22+
}
23+
24+
#[inline]
25+
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
26+
self.0.read_to_end(buf)
27+
}
28+
}
29+
30+
impl FromRawFd for Reader {
31+
#[inline]
32+
unsafe fn from_raw_fd(fd: RawFd) -> Self {
33+
Reader(Pipe(fd))
34+
}
35+
}
36+
37+
impl IntoRawFd for Reader {
38+
#[inline]
39+
fn into_raw_fd(self) -> RawFd {
40+
self.0.0
41+
}
42+
}

src/writer.rs

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
use libc::c_int;
2+
3+
use crate::pipe::Pipe;
4+
use std::{
5+
io::{self, prelude::*},
6+
os::unix::io::{FromRawFd, IntoRawFd, RawFd},
7+
};
8+
9+
#[derive(Debug)]
10+
pub struct Writer(Pipe);
11+
12+
impl Writer {
13+
pub(crate) fn new(n: c_int) -> Writer {
14+
Writer(Pipe(n))
15+
}
16+
}
17+
18+
impl Write for Writer {
19+
#[inline]
20+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
21+
self.0.write(buf)
22+
}
23+
24+
#[inline]
25+
fn flush(&mut self) -> io::Result<()> {
26+
self.0.flush()
27+
}
28+
}
29+
30+
impl FromRawFd for Writer {
31+
#[inline]
32+
unsafe fn from_raw_fd(fd: RawFd) -> Self {
33+
Writer(Pipe(fd))
34+
}
35+
}
36+
37+
impl IntoRawFd for Writer {
38+
#[inline]
39+
fn into_raw_fd(self) -> RawFd {
40+
self.0.0
41+
}
42+
}

0 commit comments

Comments
 (0)