1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use super::{AcceptedReply, RejectedReply};
use crate::bytes_ext::BytesReaderExt;
use crate::Error;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use bytes::Bytes;
use std::convert::TryFrom;
use std::io::Cursor;

const REPLY_ACCEPTED: u32 = 0;
const REPLY_DENIED: u32 = 1;

/// `ReplyBody` defines the response to an RPC invocation.
#[derive(Debug, PartialEq)]
pub enum ReplyBody<T, P>
where
    T: AsRef<[u8]>,
    P: AsRef<[u8]>,
{
    /// The server accepted the request credentials.
    Accepted(AcceptedReply<T, P>),

    /// The server rejected the request credentials.
    Denied(RejectedReply),
}

impl<'a> ReplyBody<&'a [u8], &'a [u8]> {
    pub(crate) fn from_cursor(r: &mut Cursor<&'a [u8]>) -> Result<Self, Error> {
        match r.read_u32::<BigEndian>()? {
            REPLY_ACCEPTED => Ok(ReplyBody::Accepted(AcceptedReply::from_cursor(r)?)),
            REPLY_DENIED => Ok(ReplyBody::Denied(RejectedReply::from_cursor(r)?)),
            v => Err(Error::InvalidReplyType(v)),
        }
    }
}

impl<T, P> ReplyBody<T, P>
where
    T: AsRef<[u8]>,
    P: AsRef<[u8]>,
{
    /// Serialises this `ReplyBody` into `buf`, advancing the cursor position by
    /// [`serialised_len`](ReplyBody::serialised_len) bytes.
    pub fn serialise_into(&self, buf: &mut Cursor<Vec<u8>>) -> Result<(), std::io::Error> {
        match self {
            ReplyBody::Accepted(b) => {
                buf.write_u32::<BigEndian>(REPLY_ACCEPTED)?;
                b.serialise_into(buf)
            }
            ReplyBody::Denied(b) => {
                buf.write_u32::<BigEndian>(REPLY_DENIED)?;
                b.serialise_into(buf)
            }
        }
    }

    /// Returns the on-wire length of this `ReplyBody` once serialised,
    /// including the message header.
    pub fn serialised_len(&self) -> u32 {
        let mut len = 0;

        // Discriminator
        len += 4;

        // Variant length
        len += match self {
            ReplyBody::Accepted(b) => b.serialised_len(),
            ReplyBody::Denied(b) => b.serialised_len(),
        };

        len
    }
}

impl<'a> TryFrom<&'a [u8]> for ReplyBody<&'a [u8], &'a [u8]> {
    type Error = Error;

    fn try_from(v: &'a [u8]) -> Result<Self, Self::Error> {
        let mut c = Cursor::new(v);
        ReplyBody::from_cursor(&mut c)
    }
}

impl TryFrom<Bytes> for ReplyBody<Bytes, Bytes> {
    type Error = Error;

    fn try_from(mut v: Bytes) -> Result<Self, Self::Error> {
        match v.try_u32()? {
            REPLY_ACCEPTED => Ok(ReplyBody::Accepted(AcceptedReply::try_from(v)?)),
            REPLY_DENIED => Ok(ReplyBody::Denied(RejectedReply::try_from(v)?)),
            v => Err(Error::InvalidReplyType(v)),
        }
    }
}