|
61 | 61 | -define(DOFF, 2). |
62 | 62 | -define(VAR_1_LIMIT, 16#FF). |
63 | 63 |
|
64 | | --spec build_frame(integer(), iolist()) -> iolist(). |
65 | | -build_frame(Channel, Payload) -> |
66 | | - build_frame(Channel, ?AMQP_FRAME_TYPE, Payload). |
| 64 | +-spec build_frame(non_neg_integer(), iolist()) -> iolist(). |
| 65 | +build_frame(Channel, Body) -> |
| 66 | + build_frame(Channel, ?AMQP_FRAME_TYPE, Body). |
67 | 67 |
|
68 | | -build_frame(Channel, FrameType, Payload) -> |
69 | | - Size = iolist_size(Payload) + 8, % frame header and no extension |
70 | | - [ <<Size:32/unsigned, 2:8, FrameType:8, Channel:16/unsigned>>, Payload ]. |
| 68 | +-spec build_frame(non_neg_integer(), non_neg_integer(), iolist()) -> iolist(). |
| 69 | +build_frame(Channel, FrameType, Body) -> |
| 70 | + Size = iolist_size(Body) + 8, % frame header and no extension |
| 71 | + [<<Size:32, 2:8, FrameType:8, Channel:16>>, Body]. |
71 | 72 |
|
72 | 73 | build_heartbeat_frame() -> |
73 | 74 | %% length is inclusive |
74 | 75 | <<8:32, ?DOFF:8, ?AMQP_FRAME_TYPE:8, 0:16>>. |
75 | 76 |
|
76 | | --spec generate(amqp10_type()) -> iolist(). |
77 | | -generate({described, Descriptor, Value}) -> |
78 | | - DescBin = generate(Descriptor), |
79 | | - ValueBin = generate(Value), |
80 | | - [ ?DESCRIBED_BIN, DescBin, ValueBin ]; |
81 | | - |
82 | | -generate(null) -> <<16#40>>; |
83 | | -generate(true) -> <<16#41>>; |
84 | | -generate(false) -> <<16#42>>; |
85 | | -generate({boolean, true}) -> <<16#56, 16#01>>; |
86 | | -generate({boolean, false}) -> <<16#56, 16#00>>; |
| 77 | +-spec generate(amqp10_type()) -> iodata(). |
| 78 | +generate(Type) -> |
| 79 | + case generate1(Type) of |
| 80 | + Byte when is_integer(Byte) -> |
| 81 | + [Byte]; |
| 82 | + IoData -> |
| 83 | + IoData |
| 84 | + end. |
| 85 | + |
| 86 | +generate1({described, Descriptor, Value}) -> |
| 87 | + DescBin = generate1(Descriptor), |
| 88 | + ValueBin = generate1(Value), |
| 89 | + [?DESCRIBED, DescBin, ValueBin]; |
| 90 | + |
| 91 | +generate1(null) -> 16#40; |
| 92 | +generate1(true) -> 16#41; |
| 93 | +generate1(false) -> 16#42; |
| 94 | +generate1({boolean, true}) -> [16#56, 16#01]; |
| 95 | +generate1({boolean, false}) -> [16#56, 16#00]; |
87 | 96 |
|
88 | 97 | %% some integral types have a compact encoding as a byte; this is in |
89 | 98 | %% particular for the descriptors of AMQP types, which have the domain |
90 | 99 | %% bits set to zero and values < 256. |
91 | | -generate({ubyte, V}) -> <<16#50,V:8/unsigned>>; |
92 | | -generate({ushort, V}) -> <<16#60,V:16/unsigned>>; |
93 | | -generate({uint, V}) when V =:= 0 -> <<16#43>>; |
94 | | -generate({uint, V}) when V < 256 -> <<16#52,V:8/unsigned>>; |
95 | | -generate({uint, V}) -> <<16#70,V:32/unsigned>>; |
96 | | -generate({ulong, V}) when V =:= 0 -> <<16#44>>; |
97 | | -generate({ulong, V}) when V < 256 -> <<16#53,V:8/unsigned>>; |
98 | | -generate({ulong, V}) -> <<16#80,V:64/unsigned>>; |
99 | | -generate({byte, V}) -> <<16#51,V:8/signed>>; |
100 | | -generate({short, V}) -> <<16#61,V:16/signed>>; |
101 | | -generate({int, V}) when V<128 andalso V>-129 -> <<16#54,V:8/signed>>; |
102 | | -generate({int, V}) -> <<16#71,V:32/signed>>; |
103 | | -generate({long, V}) when V<128 andalso V>-129 -> <<16#55,V:8/signed>>; |
104 | | -generate({long, V}) -> <<16#81,V:64/signed>>; |
105 | | -generate({float, V}) -> <<16#72,V:32/float>>; |
106 | | -generate({double, V}) -> <<16#82,V:64/float>>; |
107 | | -generate({char, V}) -> <<16#73,V:4/binary>>; |
108 | | -generate({timestamp,V}) -> <<16#83,V:64/signed>>; |
109 | | -generate({uuid, V}) -> <<16#98,V:16/binary>>; |
110 | | - |
111 | | -generate({utf8, V}) when size(V) < ?VAR_1_LIMIT -> [<<16#a1,(size(V)):8>>, V]; |
112 | | -generate({utf8, V}) -> [<<16#b1,(size(V)):32>>, V]; |
113 | | -generate({symbol, V}) -> [<<16#a3,(size(V)):8>>, V]; |
114 | | -generate({binary, V}) -> |
| 100 | +generate1({ubyte, V}) -> [16#50, V]; |
| 101 | +generate1({ushort, V}) -> <<16#60,V:16/unsigned>>; |
| 102 | +generate1({uint, V}) when V =:= 0 -> 16#43; |
| 103 | +generate1({uint, V}) when V < 256 -> [16#52, V]; |
| 104 | +generate1({uint, V}) -> <<16#70,V:32/unsigned>>; |
| 105 | +generate1({ulong, V}) when V =:= 0 -> 16#44; |
| 106 | +generate1({ulong, V}) when V < 256 -> [16#53, V]; |
| 107 | +generate1({ulong, V}) -> <<16#80,V:64/unsigned>>; |
| 108 | +generate1({byte, V}) -> <<16#51,V:8/signed>>; |
| 109 | +generate1({short, V}) -> <<16#61,V:16/signed>>; |
| 110 | +generate1({int, V}) when V<128 andalso V>-129 -> <<16#54,V:8/signed>>; |
| 111 | +generate1({int, V}) -> <<16#71,V:32/signed>>; |
| 112 | +generate1({long, V}) when V<128 andalso V>-129 -> <<16#55,V:8/signed>>; |
| 113 | +generate1({long, V}) -> <<16#81,V:64/signed>>; |
| 114 | +generate1({float, V}) -> <<16#72,V:32/float>>; |
| 115 | +generate1({double, V}) -> <<16#82,V:64/float>>; |
| 116 | +generate1({char, V}) -> <<16#73,V:4/binary>>; |
| 117 | +generate1({timestamp,V}) -> <<16#83,V:64/signed>>; |
| 118 | +generate1({uuid, V}) -> <<16#98,V:16/binary>>; |
| 119 | + |
| 120 | +generate1({utf8, V}) when size(V) < ?VAR_1_LIMIT -> [16#a1, size(V), V]; |
| 121 | +generate1({utf8, V}) -> [<<16#b1, (size(V)):32>>, V]; |
| 122 | +generate1({symbol, V}) -> [16#a3, size(V), V]; |
| 123 | +generate1({binary, V}) -> |
115 | 124 | Size = iolist_size(V), |
116 | | - if Size < ?VAR_1_LIMIT -> [<<16#a0,Size:8>>, V]; |
117 | | - true -> [<<16#b0,Size:32>>, V] |
| 125 | + case Size < ?VAR_1_LIMIT of |
| 126 | + true -> |
| 127 | + [16#a0, Size, V]; |
| 128 | + false -> |
| 129 | + [<<16#b0, Size:32>>, V] |
118 | 130 | end; |
119 | 131 |
|
120 | | -generate({list, []}) -> |
121 | | - <<16#45>>; |
122 | | -generate({list, List}) -> |
| 132 | +generate1({list, []}) -> |
| 133 | + 16#45; |
| 134 | +generate1({list, List}) -> |
123 | 135 | Count = length(List), |
124 | | - Compound = lists:map(fun generate/1, List), |
| 136 | + Compound = lists:map(fun generate1/1, List), |
125 | 137 | S = iolist_size(Compound), |
126 | 138 | %% If the list contains less than (256 - 1) elements and if the |
127 | 139 | %% encoded size (including the encoding of "Count", thus S + 1 |
128 | 140 | %% in the test) is less than 256 bytes, we use the short form. |
129 | 141 | %% Otherwise, we use the large form. |
130 | 142 | if Count >= (256 - 1) orelse (S + 1) >= 256 -> |
131 | | - [<<16#d0, (S + 4):32/unsigned, Count:32/unsigned>>, Compound]; |
132 | | - true -> |
133 | | - [<<16#c0, (S + 1):8/unsigned, Count:8/unsigned>>, Compound] |
| 143 | + [<<16#d0, (S + 4):32, Count:32>>, Compound]; |
| 144 | + true -> |
| 145 | + [16#c0, S + 1, Count, Compound] |
134 | 146 | end; |
135 | 147 |
|
136 | | -generate({map, ListOfPairs}) -> |
| 148 | +generate1({map, ListOfPairs}) -> |
137 | 149 | Count = length(ListOfPairs) * 2, |
138 | 150 | Compound = lists:map(fun ({Key, Val}) -> |
139 | | - [(generate(Key)), |
140 | | - (generate(Val))] |
| 151 | + [(generate1(Key)), |
| 152 | + (generate1(Val))] |
141 | 153 | end, ListOfPairs), |
142 | 154 | S = iolist_size(Compound), |
143 | | - %% See generate({list, ...}) for an explanation of this test. |
| 155 | + %% See generate1({list, ...}) for an explanation of this test. |
144 | 156 | if Count >= (256 - 1) orelse (S + 1) >= 256 -> |
145 | | - [<<16#d1, (S + 4):32, Count:32>>, Compound]; |
146 | | - true -> |
147 | | - [<<16#c1, (S + 1):8, Count:8>>, Compound] |
| 157 | + [<<16#d1, (S + 4):32, Count:32>>, Compound]; |
| 158 | + true -> |
| 159 | + [16#c1, S + 1, Count, Compound] |
148 | 160 | end; |
149 | 161 |
|
150 | | -generate({array, Type, List}) -> |
| 162 | +generate1({array, Type, List}) -> |
151 | 163 | Count = length(List), |
152 | | - Body = iolist_to_binary([constructor(Type), |
153 | | - [generate(Type, I) || I <- List]]), |
154 | | - S = size(Body), |
155 | | - %% See generate({list, ...}) for an explanation of this test. |
| 164 | + Array = [constructor(Type), |
| 165 | + [generate2(Type, I) || I <- List]], |
| 166 | + S = iolist_size(Array), |
| 167 | + %% See generate1({list, ...}) for an explanation of this test. |
156 | 168 | if Count >= (256 - 1) orelse (S + 1) >= 256 -> |
157 | | - [<<16#f0, (S + 4):32/unsigned, Count:32/unsigned>>, Body]; |
158 | | - true -> |
159 | | - [<<16#e0, (S + 1):8/unsigned, Count:8/unsigned>>, Body] |
| 169 | + [<<16#f0, (S + 4):32, Count:32>>, Array]; |
| 170 | + true -> |
| 171 | + [16#e0, S + 1, Count, Array] |
160 | 172 | end; |
161 | 173 |
|
162 | | -generate({as_is, TypeCode, Bin}) -> |
| 174 | +generate1({as_is, TypeCode, Bin}) -> |
163 | 175 | <<TypeCode, Bin>>. |
164 | 176 |
|
165 | 177 | %% TODO again these are a stub to get SASL working. New codec? Will |
166 | 178 | %% that ever happen? If not we really just need to split generate/1 |
167 | 179 | %% up into things like these... |
168 | 180 | %% for these constructors map straight-forwardly |
169 | | -constructor(symbol) -> <<16#b3>>; |
170 | | -constructor(ubyte) -> <<16#50>>; |
171 | | -constructor(ushort) -> <<16#60>>; |
172 | | -constructor(short) -> <<16#61>>; |
173 | | -constructor(uint) -> <<16#70>>; |
174 | | -constructor(ulong) -> <<16#80>>; |
175 | | -constructor(byte) -> <<16#51>>; |
176 | | -constructor(int) -> <<16#71>>; |
177 | | -constructor(long) -> <<16#81>>; |
178 | | -constructor(float) -> <<16#72>>; |
179 | | -constructor(double) -> <<16#82>>; |
180 | | -constructor(char) -> <<16#73>>; |
181 | | -constructor(timestamp) -> <<16#83>>; |
182 | | -constructor(uuid) -> <<16#98>>; |
183 | | -constructor(null) -> <<16#40>>; |
184 | | -constructor(boolean) -> <<16#56>>; |
185 | | -constructor(array) -> <<16#f0>>; % use large array type for all nested arrays |
186 | | -constructor(utf8) -> <<16#b1>>; |
| 181 | +constructor(symbol) -> 16#b3; |
| 182 | +constructor(ubyte) -> 16#50; |
| 183 | +constructor(ushort) -> 16#60; |
| 184 | +constructor(short) -> 16#61; |
| 185 | +constructor(uint) -> 16#70; |
| 186 | +constructor(ulong) -> 16#80; |
| 187 | +constructor(byte) -> 16#51; |
| 188 | +constructor(int) -> 16#71; |
| 189 | +constructor(long) -> 16#81; |
| 190 | +constructor(float) -> 16#72; |
| 191 | +constructor(double) -> 16#82; |
| 192 | +constructor(char) -> 16#73; |
| 193 | +constructor(timestamp) -> 16#83; |
| 194 | +constructor(uuid) -> 16#98; |
| 195 | +constructor(null) -> 16#40; |
| 196 | +constructor(boolean) -> 16#56; |
| 197 | +constructor(array) -> 16#f0; % use large array type for all nested arrays |
| 198 | +constructor(utf8) -> 16#b1; |
187 | 199 | constructor({described, Descriptor, Primitive}) -> |
188 | | - [<<16#00>>, generate(Descriptor), constructor(Primitive)]. |
| 200 | + [16#00, generate1(Descriptor), constructor(Primitive)]. |
189 | 201 |
|
190 | 202 | % returns io_list |
191 | | -generate(symbol, {symbol, V}) -> [<<(size(V)):32>>, V]; |
192 | | -generate(utf8, {utf8, V}) -> [<<(size(V)):32>>, V]; |
193 | | -generate(boolean, true) -> <<16#01>>; |
194 | | -generate(boolean, false) -> <<16#00>>; |
195 | | -generate(boolean, {boolean, true}) -> <<16#01>>; |
196 | | -generate(boolean, {boolean, false}) -> <<16#00>>; |
197 | | -generate(ubyte, {ubyte, V}) -> <<V:8/unsigned>>; |
198 | | -generate(byte, {byte, V}) -> <<V:8/signed>>; |
199 | | -generate(ushort, {ushort, V}) -> <<V:16/unsigned>>; |
200 | | -generate(short, {short, V}) -> <<V:16/signed>>; |
201 | | -generate(uint, {uint, V}) -> <<V:32/unsigned>>; |
202 | | -generate(int, {int, V}) -> <<V:32/signed>>; |
203 | | -generate(ulong, {ulong, V}) -> <<V:64/unsigned>>; |
204 | | -generate(long, {long, V}) -> <<V:64/signed>>; |
205 | | -generate({described, D, P}, {described, D, V}) -> |
206 | | - generate(P, V); |
207 | | -generate(array, {array, Type, List}) -> |
| 203 | +generate2(symbol, {symbol, V}) -> [<<(size(V)):32>>, V]; |
| 204 | +generate2(utf8, {utf8, V}) -> [<<(size(V)):32>>, V]; |
| 205 | +generate2(boolean, true) -> 16#01; |
| 206 | +generate2(boolean, false) -> 16#00; |
| 207 | +generate2(boolean, {boolean, true}) -> 16#01; |
| 208 | +generate2(boolean, {boolean, false}) -> 16#00; |
| 209 | +generate2(ubyte, {ubyte, V}) -> V; |
| 210 | +generate2(byte, {byte, V}) -> <<V:8/signed>>; |
| 211 | +generate2(ushort, {ushort, V}) -> <<V:16/unsigned>>; |
| 212 | +generate2(short, {short, V}) -> <<V:16/signed>>; |
| 213 | +generate2(uint, {uint, V}) -> <<V:32/unsigned>>; |
| 214 | +generate2(int, {int, V}) -> <<V:32/signed>>; |
| 215 | +generate2(ulong, {ulong, V}) -> <<V:64/unsigned>>; |
| 216 | +generate2(long, {long, V}) -> <<V:64/signed>>; |
| 217 | +generate2({described, D, P}, {described, D, V}) -> |
| 218 | + generate2(P, V); |
| 219 | +generate2(array, {array, Type, List}) -> |
208 | 220 | Count = length(List), |
209 | | - Body = iolist_to_binary([constructor(Type), |
210 | | - [generate(Type, I) || I <- List]]), |
211 | | - S = size(Body), |
212 | | - %% See generate({list, ...}) for an explanation of this test. |
213 | | - [<<(S + 4):32/unsigned, Count:32/unsigned>>, Body]. |
| 221 | + Array = [constructor(Type), |
| 222 | + [generate2(Type, I) || I <- List]], |
| 223 | + S = iolist_size(Array), |
| 224 | + %% See generate1({list, ...}) for an explanation of this test. |
| 225 | + [<<(S + 4):32, Count:32>>, Array]. |
0 commit comments