1use bacnet_encoding::primitives;
5use bacnet_encoding::tags;
6use bacnet_types::error::Error;
7use bytes::{BufMut, BytesMut};
8
9#[derive(Debug, Clone, PartialEq, Eq)]
16pub struct PrivateTransferRequest {
17 pub vendor_id: u32,
18 pub service_number: u32,
19 pub service_parameters: Option<Vec<u8>>,
21}
22
23impl PrivateTransferRequest {
24 pub fn encode(&self, buf: &mut BytesMut) {
25 primitives::encode_ctx_unsigned(buf, 0, self.vendor_id as u64);
27 primitives::encode_ctx_unsigned(buf, 1, self.service_number as u64);
29 if let Some(ref params) = self.service_parameters {
31 tags::encode_opening_tag(buf, 2);
32 buf.put_slice(params);
33 tags::encode_closing_tag(buf, 2);
34 }
35 }
36
37 pub fn decode(data: &[u8]) -> Result<Self, Error> {
38 let mut offset = 0;
39
40 let (tag, pos) = tags::decode_tag(data, offset)?;
42 let end = pos + tag.length as usize;
43 if end > data.len() {
44 return Err(Error::decoding(
45 pos,
46 "PrivateTransfer truncated at vendorID",
47 ));
48 }
49 let vendor_id = primitives::decode_unsigned(&data[pos..end])? as u32;
50 offset = end;
51
52 let (tag, pos) = tags::decode_tag(data, offset)?;
54 let end = pos + tag.length as usize;
55 if end > data.len() {
56 return Err(Error::decoding(
57 pos,
58 "PrivateTransfer truncated at serviceNumber",
59 ));
60 }
61 let service_number = primitives::decode_unsigned(&data[pos..end])? as u32;
62 offset = end;
63
64 let mut service_parameters = None;
66 if offset < data.len() {
67 let (tag, tag_end) = tags::decode_tag(data, offset)?;
68 if tag.is_opening_tag(2) {
69 let (value_bytes, new_offset) = tags::extract_context_value(data, tag_end, 2)?;
70 service_parameters = Some(value_bytes.to_vec());
71 offset = new_offset;
72 let _ = offset;
73 }
74 }
75
76 Ok(Self {
77 vendor_id,
78 service_number,
79 service_parameters,
80 })
81 }
82}
83
84#[derive(Debug, Clone, PartialEq, Eq)]
90pub struct PrivateTransferAck {
91 pub vendor_id: u32,
92 pub service_number: u32,
93 pub result_block: Option<Vec<u8>>,
95}
96
97impl PrivateTransferAck {
98 pub fn encode(&self, buf: &mut BytesMut) {
99 primitives::encode_ctx_unsigned(buf, 0, self.vendor_id as u64);
101 primitives::encode_ctx_unsigned(buf, 1, self.service_number as u64);
103 if let Some(ref block) = self.result_block {
105 tags::encode_opening_tag(buf, 2);
106 buf.put_slice(block);
107 tags::encode_closing_tag(buf, 2);
108 }
109 }
110
111 pub fn decode(data: &[u8]) -> Result<Self, Error> {
112 let mut offset = 0;
113
114 let (tag, pos) = tags::decode_tag(data, offset)?;
116 let end = pos + tag.length as usize;
117 if end > data.len() {
118 return Err(Error::decoding(
119 pos,
120 "PrivateTransferAck truncated at vendorID",
121 ));
122 }
123 let vendor_id = primitives::decode_unsigned(&data[pos..end])? as u32;
124 offset = end;
125
126 let (tag, pos) = tags::decode_tag(data, offset)?;
128 let end = pos + tag.length as usize;
129 if end > data.len() {
130 return Err(Error::decoding(
131 pos,
132 "PrivateTransferAck truncated at serviceNumber",
133 ));
134 }
135 let service_number = primitives::decode_unsigned(&data[pos..end])? as u32;
136 offset = end;
137
138 let mut result_block = None;
140 if offset < data.len() {
141 let (tag, tag_end) = tags::decode_tag(data, offset)?;
142 if tag.is_opening_tag(2) {
143 let (value_bytes, new_offset) = tags::extract_context_value(data, tag_end, 2)?;
144 result_block = Some(value_bytes.to_vec());
145 offset = new_offset;
146 let _ = offset;
147 }
148 }
149
150 Ok(Self {
151 vendor_id,
152 service_number,
153 result_block,
154 })
155 }
156}
157
158#[cfg(test)]
159mod tests {
160 use super::*;
161
162 #[test]
163 fn request_round_trip() {
164 let req = PrivateTransferRequest {
165 vendor_id: 42,
166 service_number: 7,
167 service_parameters: Some(vec![0x21, 0x05]),
168 };
169 let mut buf = BytesMut::new();
170 req.encode(&mut buf);
171 let decoded = PrivateTransferRequest::decode(&buf).unwrap();
172 assert_eq!(req, decoded);
173 }
174
175 #[test]
176 fn request_no_params_round_trip() {
177 let req = PrivateTransferRequest {
178 vendor_id: 999,
179 service_number: 1,
180 service_parameters: None,
181 };
182 let mut buf = BytesMut::new();
183 req.encode(&mut buf);
184 let decoded = PrivateTransferRequest::decode(&buf).unwrap();
185 assert_eq!(req, decoded);
186 }
187
188 #[test]
189 fn ack_round_trip() {
190 let ack = PrivateTransferAck {
191 vendor_id: 42,
192 service_number: 7,
193 result_block: Some(vec![0x44, 0x42, 0x90, 0x00, 0x00]),
194 };
195 let mut buf = BytesMut::new();
196 ack.encode(&mut buf);
197 let decoded = PrivateTransferAck::decode(&buf).unwrap();
198 assert_eq!(ack, decoded);
199 }
200
201 #[test]
202 fn ack_no_result_round_trip() {
203 let ack = PrivateTransferAck {
204 vendor_id: 100,
205 service_number: 3,
206 result_block: None,
207 };
208 let mut buf = BytesMut::new();
209 ack.encode(&mut buf);
210 let decoded = PrivateTransferAck::decode(&buf).unwrap();
211 assert_eq!(ack, decoded);
212 }
213
214 #[test]
219 fn test_decode_request_empty_input() {
220 assert!(PrivateTransferRequest::decode(&[]).is_err());
221 }
222
223 #[test]
224 fn test_decode_request_truncated_1_byte() {
225 let req = PrivateTransferRequest {
226 vendor_id: 42,
227 service_number: 7,
228 service_parameters: Some(vec![0x21, 0x05]),
229 };
230 let mut buf = BytesMut::new();
231 req.encode(&mut buf);
232 assert!(PrivateTransferRequest::decode(&buf[..1]).is_err());
233 }
234
235 #[test]
236 fn test_decode_request_truncated_half() {
237 let req = PrivateTransferRequest {
238 vendor_id: 42,
239 service_number: 7,
240 service_parameters: Some(vec![0x21, 0x05, 0x44, 0x42, 0x90, 0x00, 0x00]),
241 };
242 let mut buf = BytesMut::new();
243 req.encode(&mut buf);
244 let half = buf.len() / 2;
245 assert!(PrivateTransferRequest::decode(&buf[..half]).is_err());
246 }
247
248 #[test]
249 fn test_decode_request_invalid_tag() {
250 assert!(PrivateTransferRequest::decode(&[0xFF, 0xFF, 0xFF]).is_err());
251 }
252
253 #[test]
254 fn test_decode_ack_empty_input() {
255 assert!(PrivateTransferAck::decode(&[]).is_err());
256 }
257
258 #[test]
259 fn test_decode_ack_truncated_1_byte() {
260 let ack = PrivateTransferAck {
261 vendor_id: 42,
262 service_number: 7,
263 result_block: Some(vec![0x44, 0x42]),
264 };
265 let mut buf = BytesMut::new();
266 ack.encode(&mut buf);
267 assert!(PrivateTransferAck::decode(&buf[..1]).is_err());
268 }
269
270 #[test]
271 fn test_decode_ack_invalid_tag() {
272 assert!(PrivateTransferAck::decode(&[0xFF, 0xFF, 0xFF]).is_err());
273 }
274}