1use crate::encoding::{
8    self, DynamicFlags, EpitaphBody, NoHandleResourceDialect, TransactionHeader,
9    TransactionMessage, TransactionMessageType,
10};
11use crate::error::Error;
12use crate::{AsyncChannel, Channel, TransportError};
13use zx_status;
14
15pub trait ChannelEpitaphExt {
17    fn close_with_epitaph(self, status: zx_status::Status) -> Result<(), Error>;
19}
20
21impl<T: ChannelLike> ChannelEpitaphExt for T {
22    fn close_with_epitaph(self, status: zx_status::Status) -> Result<(), Error> {
23        write_epitaph_impl(&self, status)
24    }
25}
26
27pub trait ChannelLike {
29    fn write_epitaph(&self, bytes: &[u8]) -> Result<(), TransportError>;
31}
32
33impl ChannelLike for Channel {
34    fn write_epitaph(&self, bytes: &[u8]) -> Result<(), TransportError> {
35        self.write_etc(bytes, &mut []).map_err(Into::into)
36    }
37}
38
39impl ChannelLike for AsyncChannel {
40    fn write_epitaph(&self, bytes: &[u8]) -> Result<(), TransportError> {
41        self.write_etc(bytes, &mut []).map_err(Into::into)
42    }
43}
44
45pub(crate) fn write_epitaph_impl<T: ChannelLike>(
46    channel: &T,
47    status: zx_status::Status,
48) -> Result<(), Error> {
49    let msg = TransactionMessage {
50        header: TransactionHeader::new(0, encoding::EPITAPH_ORDINAL, DynamicFlags::empty()),
51        body: &EpitaphBody { error: status },
52    };
53    encoding::with_tls_encoded::<TransactionMessageType<EpitaphBody>, NoHandleResourceDialect, ()>(
54        msg,
55        |bytes, handles| {
56            assert!(handles.is_empty(), "Epitaph should not have handles!");
57            match channel.write_epitaph(bytes) {
58                Ok(()) | Err(TransportError::Status(zx_status::Status::PEER_CLOSED)) => Ok(()),
59                Err(e) => Err(Error::ServerEpitaphWrite(e)),
60            }
61        },
62    )
63}