use {HandleBase, Handle, HandleRef, Peered};
use {sys, Status, into_result};
use std::ptr;
#[derive(Debug, Eq, PartialEq)]
pub struct Socket(Handle);
impl HandleBase for Socket {
fn get_ref(&self) -> HandleRef {
self.0.get_ref()
}
fn from_handle(handle: Handle) -> Self {
Socket(handle)
}
}
impl Peered for Socket {
}
#[repr(u32)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum SocketOpts {
Default = 0,
}
impl Default for SocketOpts {
fn default() -> Self {
SocketOpts::Default
}
}
#[repr(u32)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum SocketWriteOpts {
Default = 0,
}
impl Default for SocketWriteOpts {
fn default() -> Self {
SocketWriteOpts::Default
}
}
#[repr(u32)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum SocketReadOpts {
Default = 0,
}
impl Default for SocketReadOpts {
fn default() -> Self {
SocketReadOpts::Default
}
}
impl Socket {
pub fn create(opts: SocketOpts) -> Result<(Socket, Socket), Status> {
unsafe {
let mut out0 = 0;
let mut out1 = 0;
let status = sys::mx_socket_create(opts as u32, &mut out0, &mut out1);
into_result(status, ||
(Self::from_handle(Handle(out0)),
Self::from_handle(Handle(out1))))
}
}
pub fn write(&self, opts: SocketWriteOpts, bytes: &[u8]) -> Result<usize, Status> {
let mut actual = 0;
let status = unsafe {
sys::mx_socket_write(self.raw_handle(), opts as u32, bytes.as_ptr(), bytes.len(),
&mut actual)
};
into_result(status, || actual)
}
pub fn read(&self, opts: SocketReadOpts, bytes: &mut [u8]) -> Result<usize, Status> {
let mut actual = 0;
let status = unsafe {
sys::mx_socket_read(self.raw_handle(), opts as u32, bytes.as_mut_ptr(),
bytes.len(), &mut actual)
};
if status != sys::MX_OK {
actual = 0;
}
into_result(status, || actual)
}
pub fn half_close(&self) -> Result<(), Status> {
let status = unsafe { sys::mx_socket_write(self.raw_handle(), sys::MX_SOCKET_HALF_CLOSE,
ptr::null(), 0, ptr::null_mut()) };
into_result(status, || ())
}
pub fn outstanding_read_bytes(&self) -> Result<usize, Status> {
let mut outstanding = 0;
let status = unsafe {
sys::mx_socket_read(self.raw_handle(), 0, ptr::null_mut(), 0, &mut outstanding)
};
into_result(status, || outstanding)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn socket_basic() {
let (s1, s2) = Socket::create(SocketOpts::Default).unwrap();
assert_eq!(s1.write(SocketWriteOpts::Default, b"hello").unwrap(), 5);
let mut read_vec = vec![0; 8];
assert_eq!(s2.read(SocketReadOpts::Default, &mut read_vec).unwrap(), 5);
assert_eq!(&read_vec[0..5], b"hello");
assert_eq!(s2.read(SocketReadOpts::Default, &mut read_vec), Err(Status::ErrShouldWait));
assert!(s1.half_close().is_ok());
assert_eq!(s2.read(SocketReadOpts::Default, &mut read_vec), Err(Status::ErrPeerClosed));
assert_eq!(s1.write(SocketWriteOpts::Default, b"fail"), Err(Status::ErrBadState));
assert_eq!(s1.read(SocketReadOpts::Default, &mut read_vec), Err(Status::ErrShouldWait));
assert_eq!(s2.write(SocketWriteOpts::Default, b"back").unwrap(), 4);
assert_eq!(s1.read(SocketReadOpts::Default, &mut read_vec).unwrap(), 4);
assert_eq!(&read_vec[0..4], b"back");
}
}