1use bacnet_types::primitives::{Date, ObjectIdentifier, Time};
4#[cfg(feature = "alloc")]
5use bytes::BytesMut;
6
7use crate::sink::{EncodeSink, SinkFull};
8use crate::tags::{self, TagClass, app_tag};
9
10#[cfg(feature = "alloc")]
12pub fn encode_unsigned(buf: &mut BytesMut, value: u64) {
13 encode_unsigned_to_sink(buf, value).expect("the BytesMut sink cannot return SinkFull");
14}
15
16#[cfg(feature = "alloc")]
18pub fn encode_signed(buf: &mut BytesMut, value: i32) {
19 encode_signed_to_sink(buf, value).expect("the BytesMut sink cannot return SinkFull");
20}
21
22#[cfg(feature = "alloc")]
24pub fn encode_real(buf: &mut BytesMut, value: f32) {
25 encode_real_to_sink(buf, value).expect("the BytesMut sink cannot return SinkFull");
26}
27
28#[cfg(feature = "alloc")]
30pub fn encode_double(buf: &mut BytesMut, value: f64) {
31 encode_double_to_sink(buf, value).expect("the BytesMut sink cannot return SinkFull");
32}
33
34#[cfg(feature = "alloc")]
36pub fn encode_app_null(buf: &mut BytesMut) {
37 encode_app_null_to_sink(buf).expect("the BytesMut sink cannot return SinkFull");
38}
39
40#[cfg(feature = "alloc")]
44pub fn encode_app_boolean(buf: &mut BytesMut, value: bool) {
45 encode_app_boolean_to_sink(buf, value).expect("the BytesMut sink cannot return SinkFull");
46}
47
48#[cfg(feature = "alloc")]
50pub fn encode_app_unsigned(buf: &mut BytesMut, value: u64) {
51 encode_app_unsigned_to_sink(buf, value).expect("the BytesMut sink cannot return SinkFull");
52}
53
54#[cfg(feature = "alloc")]
56pub fn encode_app_signed(buf: &mut BytesMut, value: i32) {
57 encode_app_signed_to_sink(buf, value).expect("the BytesMut sink cannot return SinkFull");
58}
59
60#[cfg(feature = "alloc")]
62pub fn encode_app_real(buf: &mut BytesMut, value: f32) {
63 encode_app_real_to_sink(buf, value).expect("the BytesMut sink cannot return SinkFull");
64}
65
66#[cfg(feature = "alloc")]
68pub fn encode_app_double(buf: &mut BytesMut, value: f64) {
69 encode_app_double_to_sink(buf, value).expect("the BytesMut sink cannot return SinkFull");
70}
71
72#[cfg(feature = "alloc")]
74pub fn encode_app_enumerated(buf: &mut BytesMut, value: u32) {
75 encode_app_enumerated_to_sink(buf, value).expect("the BytesMut sink cannot return SinkFull");
76}
77
78#[cfg(feature = "alloc")]
80pub fn encode_app_date(buf: &mut BytesMut, date: &Date) {
81 encode_app_date_to_sink(buf, date).expect("the BytesMut sink cannot return SinkFull");
82}
83
84#[cfg(feature = "alloc")]
86pub fn encode_app_time(buf: &mut BytesMut, time: &Time) {
87 encode_app_time_to_sink(buf, time).expect("the BytesMut sink cannot return SinkFull");
88}
89
90#[cfg(feature = "alloc")]
92pub fn encode_app_object_id(buf: &mut BytesMut, oid: &ObjectIdentifier) {
93 encode_app_object_id_to_sink(buf, oid).expect("the BytesMut sink cannot return SinkFull");
94}
95
96#[cfg(feature = "alloc")]
98pub fn encode_ctx_unsigned(buf: &mut BytesMut, tag: u8, value: u64) {
99 encode_ctx_unsigned_to_sink(buf, tag, value).expect("the BytesMut sink cannot return SinkFull");
100}
101
102#[cfg(feature = "alloc")]
104pub fn encode_ctx_signed(buf: &mut BytesMut, tag: u8, value: i32) {
105 encode_ctx_signed_to_sink(buf, tag, value).expect("the BytesMut sink cannot return SinkFull");
106}
107
108#[cfg(feature = "alloc")]
110pub fn encode_ctx_real(buf: &mut BytesMut, tag: u8, value: f32) {
111 encode_ctx_real_to_sink(buf, tag, value).expect("the BytesMut sink cannot return SinkFull");
112}
113
114#[cfg(feature = "alloc")]
116pub fn encode_ctx_double(buf: &mut BytesMut, tag: u8, value: f64) {
117 encode_ctx_double_to_sink(buf, tag, value).expect("the BytesMut sink cannot return SinkFull");
118}
119
120#[cfg(feature = "alloc")]
122pub fn encode_ctx_enumerated(buf: &mut BytesMut, tag: u8, value: u32) {
123 encode_ctx_enumerated_to_sink(buf, tag, value)
124 .expect("the BytesMut sink cannot return SinkFull");
125}
126
127#[cfg(feature = "alloc")]
131pub fn encode_ctx_boolean(buf: &mut BytesMut, tag: u8, value: bool) {
132 encode_ctx_boolean_to_sink(buf, tag, value).expect("the BytesMut sink cannot return SinkFull");
133}
134
135#[cfg(feature = "alloc")]
137pub fn encode_ctx_object_id(buf: &mut BytesMut, tag: u8, oid: &ObjectIdentifier) {
138 encode_ctx_object_id_to_sink(buf, tag, oid).expect("the BytesMut sink cannot return SinkFull");
139}
140
141#[cfg(feature = "alloc")]
143pub fn encode_ctx_date(buf: &mut BytesMut, tag: u8, date: &Date) {
144 encode_ctx_date_to_sink(buf, tag, date).expect("the BytesMut sink cannot return SinkFull");
145}
146
147pub fn unsigned_len(value: u64) -> u32 {
149 if value <= 0xFF {
150 1
151 } else if value <= 0xFFFF {
152 2
153 } else if value <= 0xFF_FFFF {
154 3
155 } else if value <= 0xFFFF_FFFF {
156 4
157 } else if value <= 0xFF_FFFF_FFFF {
158 5
159 } else if value <= 0xFFFF_FFFF_FFFF {
160 6
161 } else if value <= 0xFF_FFFF_FFFF_FFFF {
162 7
163 } else {
164 8
165 }
166}
167
168pub fn signed_len(value: i32) -> u32 {
170 if (-128..=127).contains(&value) {
171 1
172 } else if (-32768..=32767).contains(&value) {
173 2
174 } else if (-8_388_608..=8_388_607).contains(&value) {
175 3
176 } else {
177 4
178 }
179}
180
181pub fn encode_unsigned_to_sink<S: EncodeSink + ?Sized>(
185 sink: &mut S,
186 value: u64,
187) -> Result<usize, SinkFull> {
188 write_scalar(
189 sink,
190 &value.to_be_bytes()[8 - unsigned_len(value) as usize..],
191 )
192}
193
194pub fn encode_signed_to_sink<S: EncodeSink + ?Sized>(
198 sink: &mut S,
199 value: i32,
200) -> Result<usize, SinkFull> {
201 write_scalar(sink, &value.to_be_bytes()[4 - signed_len(value) as usize..])
202}
203
204pub fn encode_real_to_sink<S: EncodeSink + ?Sized>(
208 sink: &mut S,
209 value: f32,
210) -> Result<usize, SinkFull> {
211 write_scalar(sink, &value.to_bits().to_be_bytes())
212}
213
214pub fn encode_double_to_sink<S: EncodeSink + ?Sized>(
218 sink: &mut S,
219 value: f64,
220) -> Result<usize, SinkFull> {
221 write_scalar(sink, &value.to_bits().to_be_bytes())
222}
223
224pub fn encode_app_null_to_sink<S: EncodeSink + ?Sized>(sink: &mut S) -> Result<usize, SinkFull> {
228 write_tagged(sink, app_tag::NULL, TagClass::Application, 0, &[])
229}
230
231pub fn encode_app_boolean_to_sink<S: EncodeSink + ?Sized>(
235 sink: &mut S,
236 value: bool,
237) -> Result<usize, SinkFull> {
238 write_tagged(
239 sink,
240 app_tag::BOOLEAN,
241 TagClass::Application,
242 u32::from(value),
243 &[],
244 )
245}
246
247pub fn encode_app_unsigned_to_sink<S: EncodeSink + ?Sized>(
251 sink: &mut S,
252 value: u64,
253) -> Result<usize, SinkFull> {
254 write_tagged(
255 sink,
256 app_tag::UNSIGNED,
257 TagClass::Application,
258 unsigned_len(value),
259 &value.to_be_bytes()[8 - unsigned_len(value) as usize..],
260 )
261}
262
263pub fn encode_app_signed_to_sink<S: EncodeSink + ?Sized>(
267 sink: &mut S,
268 value: i32,
269) -> Result<usize, SinkFull> {
270 write_tagged(
271 sink,
272 app_tag::SIGNED,
273 TagClass::Application,
274 signed_len(value),
275 &value.to_be_bytes()[4 - signed_len(value) as usize..],
276 )
277}
278
279pub fn encode_app_real_to_sink<S: EncodeSink + ?Sized>(
283 sink: &mut S,
284 value: f32,
285) -> Result<usize, SinkFull> {
286 write_tagged(
287 sink,
288 app_tag::REAL,
289 TagClass::Application,
290 4,
291 &value.to_bits().to_be_bytes(),
292 )
293}
294
295pub fn encode_app_double_to_sink<S: EncodeSink + ?Sized>(
299 sink: &mut S,
300 value: f64,
301) -> Result<usize, SinkFull> {
302 write_tagged(
303 sink,
304 app_tag::DOUBLE,
305 TagClass::Application,
306 8,
307 &value.to_bits().to_be_bytes(),
308 )
309}
310
311pub fn encode_app_enumerated_to_sink<S: EncodeSink + ?Sized>(
315 sink: &mut S,
316 value: u32,
317) -> Result<usize, SinkFull> {
318 write_tagged(
319 sink,
320 app_tag::ENUMERATED,
321 TagClass::Application,
322 unsigned_len(u64::from(value)),
323 &value.to_be_bytes()[4 - unsigned_len(u64::from(value)) as usize..],
324 )
325}
326
327pub fn encode_app_date_to_sink<S: EncodeSink + ?Sized>(
331 sink: &mut S,
332 date: &Date,
333) -> Result<usize, SinkFull> {
334 write_tagged(
335 sink,
336 app_tag::DATE,
337 TagClass::Application,
338 4,
339 &date.encode(),
340 )
341}
342
343pub fn encode_app_time_to_sink<S: EncodeSink + ?Sized>(
347 sink: &mut S,
348 time: &Time,
349) -> Result<usize, SinkFull> {
350 write_tagged(
351 sink,
352 app_tag::TIME,
353 TagClass::Application,
354 4,
355 &time.encode(),
356 )
357}
358
359pub fn encode_app_object_id_to_sink<S: EncodeSink + ?Sized>(
363 sink: &mut S,
364 oid: &ObjectIdentifier,
365) -> Result<usize, SinkFull> {
366 write_tagged(
367 sink,
368 app_tag::OBJECT_IDENTIFIER,
369 TagClass::Application,
370 4,
371 &oid.encode(),
372 )
373}
374
375pub fn encode_ctx_unsigned_to_sink<S: EncodeSink + ?Sized>(
391 sink: &mut S,
392 tag: u8,
393 value: u64,
394) -> Result<usize, SinkFull> {
395 write_tagged(
396 sink,
397 tag,
398 TagClass::Context,
399 unsigned_len(value),
400 &value.to_be_bytes()[8 - unsigned_len(value) as usize..],
401 )
402}
403
404pub fn encode_ctx_signed_to_sink<S: EncodeSink + ?Sized>(
409 sink: &mut S,
410 tag: u8,
411 value: i32,
412) -> Result<usize, SinkFull> {
413 write_tagged(
414 sink,
415 tag,
416 TagClass::Context,
417 signed_len(value),
418 &value.to_be_bytes()[4 - signed_len(value) as usize..],
419 )
420}
421
422pub fn encode_ctx_real_to_sink<S: EncodeSink + ?Sized>(
427 sink: &mut S,
428 tag: u8,
429 value: f32,
430) -> Result<usize, SinkFull> {
431 write_tagged(
432 sink,
433 tag,
434 TagClass::Context,
435 4,
436 &value.to_bits().to_be_bytes(),
437 )
438}
439
440pub fn encode_ctx_double_to_sink<S: EncodeSink + ?Sized>(
445 sink: &mut S,
446 tag: u8,
447 value: f64,
448) -> Result<usize, SinkFull> {
449 write_tagged(
450 sink,
451 tag,
452 TagClass::Context,
453 8,
454 &value.to_bits().to_be_bytes(),
455 )
456}
457
458pub fn encode_ctx_enumerated_to_sink<S: EncodeSink + ?Sized>(
463 sink: &mut S,
464 tag: u8,
465 value: u32,
466) -> Result<usize, SinkFull> {
467 write_tagged(
468 sink,
469 tag,
470 TagClass::Context,
471 unsigned_len(u64::from(value)),
472 &value.to_be_bytes()[4 - unsigned_len(u64::from(value)) as usize..],
473 )
474}
475
476pub fn encode_ctx_boolean_to_sink<S: EncodeSink + ?Sized>(
481 sink: &mut S,
482 tag: u8,
483 value: bool,
484) -> Result<usize, SinkFull> {
485 write_tagged(sink, tag, TagClass::Context, 1, &[u8::from(value)])
486}
487
488pub fn encode_ctx_object_id_to_sink<S: EncodeSink + ?Sized>(
493 sink: &mut S,
494 tag: u8,
495 oid: &ObjectIdentifier,
496) -> Result<usize, SinkFull> {
497 write_tagged(sink, tag, TagClass::Context, 4, &oid.encode())
498}
499
500pub fn encode_ctx_date_to_sink<S: EncodeSink + ?Sized>(
505 sink: &mut S,
506 tag: u8,
507 date: &Date,
508) -> Result<usize, SinkFull> {
509 write_tagged(sink, tag, TagClass::Context, 4, &date.encode())
510}
511
512fn write_tagged<S: EncodeSink + ?Sized>(
515 sink: &mut S,
516 tag: u8,
517 class: TagClass,
518 length: u32,
519 contents: &[u8],
520) -> Result<usize, SinkFull> {
521 let mut encoded = [0; 11];
522 let header = tags::encode_tag_to_sink(&mut &mut encoded[..], tag, class, length)
523 .expect("a scalar header fits the eleven-byte staging buffer");
524 let used = header + contents.len();
525 encoded[header..used].copy_from_slice(contents);
526 write_scalar(sink, &encoded[..used])
527}
528
529fn write_scalar<S: EncodeSink + ?Sized>(sink: &mut S, encoded: &[u8]) -> Result<usize, SinkFull> {
530 if let Some(available) = sink.remaining_capacity()
531 && available < encoded.len()
532 {
533 return Err(SinkFull {
534 needed: encoded.len(),
535 available,
536 });
537 }
538 sink.write(encoded)?;
539 Ok(encoded.len())
540}