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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use crate::io::Encode;
use crate::postgres::io::PgBufMutExt;
use crate::postgres::types::Oid;

const DESCRIBE_PORTAL: u8 = b'P';
const DESCRIBE_STATEMENT: u8 = b'S';

// [Describe] will emit both a [RowDescription] and a [ParameterDescription] message

#[derive(Debug)]
#[allow(dead_code)]
pub enum Describe {
    UnnamedStatement,
    Statement(Oid),

    UnnamedPortal,
    Portal(Oid),
}

impl Encode<'_> for Describe {
    fn encode_with(&self, buf: &mut Vec<u8>, _: ()) {
        // 15 bytes for 1-digit statement/portal IDs
        buf.reserve(20);
        buf.push(b'D');

        buf.put_length_prefixed(|buf| {
            match self {
                // #[likely]
                Describe::Statement(id) => {
                    buf.push(DESCRIBE_STATEMENT);
                    buf.put_statement_name(*id);
                }

                Describe::UnnamedPortal => {
                    buf.push(DESCRIBE_PORTAL);
                    buf.push(0);
                }

                Describe::UnnamedStatement => {
                    buf.push(DESCRIBE_STATEMENT);
                    buf.push(0);
                }

                Describe::Portal(id) => {
                    buf.push(DESCRIBE_PORTAL);
                    buf.put_portal_name(Some(*id));
                }
            }
        });
    }
}

#[test]
fn test_encode_describe_portal() {
    const EXPECTED: &[u8] = b"D\0\0\0\x0EPsqlx_p_5\0";

    let mut buf = Vec::new();
    let m = Describe::Portal(Oid(5));

    m.encode(&mut buf);

    assert_eq!(buf, EXPECTED);
}

#[test]
fn test_encode_describe_unnamed_portal() {
    const EXPECTED: &[u8] = b"D\0\0\0\x06P\0";

    let mut buf = Vec::new();
    let m = Describe::UnnamedPortal;

    m.encode(&mut buf);

    assert_eq!(buf, EXPECTED);
}

#[test]
fn test_encode_describe_statement() {
    const EXPECTED: &[u8] = b"D\0\0\0\x0ESsqlx_s_5\0";

    let mut buf = Vec::new();
    let m = Describe::Statement(Oid(5));

    m.encode(&mut buf);

    assert_eq!(buf, EXPECTED);
}

#[test]
fn test_encode_describe_unnamed_statement() {
    const EXPECTED: &[u8] = b"D\0\0\0\x06S\0";

    let mut buf = Vec::new();
    let m = Describe::UnnamedStatement;

    m.encode(&mut buf);

    assert_eq!(buf, EXPECTED);
}

#[cfg(all(test, not(debug_assertions)))]
#[bench]
fn bench_encode_describe_portal(b: &mut test::Bencher) {
    use test::black_box;

    let mut buf = Vec::with_capacity(128);

    b.iter(|| {
        buf.clear();

        black_box(Describe::Portal(5)).encode(&mut buf);
    });
}

#[cfg(all(test, not(debug_assertions)))]
#[bench]
fn bench_encode_describe_unnamed_statement(b: &mut test::Bencher) {
    use test::black_box;

    let mut buf = Vec::with_capacity(128);

    b.iter(|| {
        buf.clear();

        black_box(Describe::UnnamedStatement).encode(&mut buf);
    });
}