onc_rpc/reply/
reply_body.rs1use std::{
2 convert::TryFrom,
3 io::{Cursor, Write},
4};
5
6use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
7
8use super::{AcceptedReply, RejectedReply};
9use crate::Error;
10
11const REPLY_ACCEPTED: u32 = 0;
12const REPLY_DENIED: u32 = 1;
13
14#[derive(Debug, PartialEq)]
16pub enum ReplyBody<T, P>
17where
18 T: AsRef<[u8]>,
19 P: AsRef<[u8]>,
20{
21 Accepted(AcceptedReply<T, P>),
23
24 Denied(RejectedReply),
26}
27
28impl<'a> ReplyBody<&'a [u8], &'a [u8]> {
29 pub(crate) fn from_cursor(r: &mut Cursor<&'a [u8]>) -> Result<Self, Error> {
30 match r.read_u32::<BigEndian>()? {
31 REPLY_ACCEPTED => Ok(ReplyBody::Accepted(AcceptedReply::from_cursor(r)?)),
32 REPLY_DENIED => Ok(ReplyBody::Denied(RejectedReply::from_cursor(r)?)),
33 v => Err(Error::InvalidReplyType(v)),
34 }
35 }
36}
37
38impl<T, P> ReplyBody<T, P>
39where
40 T: AsRef<[u8]>,
41 P: AsRef<[u8]>,
42{
43 pub fn serialise_into<W: Write>(&self, mut buf: W) -> Result<(), std::io::Error> {
46 match self {
47 Self::Accepted(b) => {
48 buf.write_u32::<BigEndian>(REPLY_ACCEPTED)?;
49 b.serialise_into(buf)
50 }
51 Self::Denied(b) => {
52 buf.write_u32::<BigEndian>(REPLY_DENIED)?;
53 b.serialise_into(buf)
54 }
55 }
56 }
57
58 pub fn serialised_len(&self) -> u32 {
61 let mut len = 0;
62
63 len += 4;
65
66 len += match self {
68 Self::Accepted(b) => b.serialised_len(),
69 Self::Denied(b) => b.serialised_len(),
70 };
71
72 len
73 }
74}
75
76impl<'a> TryFrom<&'a [u8]> for ReplyBody<&'a [u8], &'a [u8]> {
77 type Error = Error;
78
79 fn try_from(v: &'a [u8]) -> Result<Self, Self::Error> {
80 let mut c = Cursor::new(v);
81 ReplyBody::from_cursor(&mut c)
82 }
83}
84
85#[cfg(feature = "bytes")]
86impl TryFrom<crate::Bytes> for ReplyBody<crate::Bytes, crate::Bytes> {
87 type Error = Error;
88
89 fn try_from(mut v: crate::Bytes) -> Result<Self, Self::Error> {
90 use crate::bytes_ext::BytesReaderExt;
91
92 match v.try_u32()? {
93 REPLY_ACCEPTED => Ok(Self::Accepted(AcceptedReply::try_from(v)?)),
94 REPLY_DENIED => Ok(Self::Denied(RejectedReply::try_from(v)?)),
95 v => Err(Error::InvalidReplyType(v)),
96 }
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use crate::auth::AuthFlavor;
103
104 use super::*;
105
106 #[test]
109 fn test_differing_payload_type() {
110 let binding = vec![42];
111 let auth = AuthFlavor::AuthNone(Some(binding.as_slice()));
112 let payload = [42, 42, 42, 42];
113
114 let _reply: ReplyBody<&[u8], [u8; 4]> = ReplyBody::Accepted(AcceptedReply::new(
115 auth,
116 crate::AcceptedStatus::Success(payload),
117 ));
118 }
119}