use crate::encoding::{
self, DynamicFlags, EpitaphBody, NoHandleResourceDialect, TransactionHeader,
TransactionMessage, TransactionMessageType,
};
use crate::error::Error;
use crate::{AsyncChannel, Channel, TransportError};
use zx_status;
pub trait ChannelEpitaphExt {
fn close_with_epitaph(self, status: zx_status::Status) -> Result<(), Error>;
}
impl ChannelEpitaphExt for Channel {
fn close_with_epitaph(self, status: zx_status::Status) -> Result<(), Error> {
write_epitaph_impl(&self, status)
}
}
impl ChannelEpitaphExt for AsyncChannel {
fn close_with_epitaph(self, status: zx_status::Status) -> Result<(), Error> {
write_epitaph_impl(&self, status)
}
}
pub trait ChannelLike {
fn write_epitaph(&self, bytes: &[u8]) -> Result<(), TransportError>;
}
impl ChannelLike for Channel {
fn write_epitaph(&self, bytes: &[u8]) -> Result<(), TransportError> {
self.write_etc(bytes, &mut []).map_err(Into::into)
}
}
impl ChannelLike for AsyncChannel {
fn write_epitaph(&self, bytes: &[u8]) -> Result<(), TransportError> {
self.write_etc(bytes, &mut []).map_err(Into::into)
}
}
pub(crate) fn write_epitaph_impl<T: ChannelLike>(
channel: &T,
status: zx_status::Status,
) -> Result<(), Error> {
let msg = TransactionMessage {
header: TransactionHeader::new(0, encoding::EPITAPH_ORDINAL, DynamicFlags::empty()),
body: &EpitaphBody { error: status },
};
encoding::with_tls_encoded::<TransactionMessageType<EpitaphBody>, NoHandleResourceDialect, ()>(
msg,
|bytes, handles| {
assert!(handles.is_empty(), "Epitaph should not have handles!");
match channel.write_epitaph(bytes) {
Ok(()) | Err(TransportError::Status(zx_status::Status::PEER_CLOSED)) => Ok(()),
Err(e) => Err(Error::ServerEpitaphWrite(e)),
}
},
)
}