1use spacepackets::{
2 cfdp::{
3 tlv::{GenericTlv, Tlv, TlvType},
4 SegmentationControl, TransmissionMode,
5 },
6 util::UnsignedByteField,
7};
8
9#[cfg(feature = "alloc")]
10pub use alloc_mod::*;
11
12#[derive(Debug, PartialEq, Eq)]
13#[cfg_attr(feature = "defmt", derive(defmt::Format))]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15pub struct FilePathTooLarge(pub usize);
16
17pub trait ReadablePutRequest {
20 fn destination_id(&self) -> UnsignedByteField;
21 fn source_file(&self) -> Option<&str>;
22 fn dest_file(&self) -> Option<&str>;
23 fn trans_mode(&self) -> Option<TransmissionMode>;
24 fn closure_requested(&self) -> Option<bool>;
25 fn seg_ctrl(&self) -> Option<SegmentationControl>;
26
27 fn msgs_to_user(&self) -> Option<impl Iterator<Item = Tlv>>;
28 fn fault_handler_overrides(&self) -> Option<impl Iterator<Item = Tlv>>;
29 fn flow_label(&self) -> Option<Tlv>;
30 fn fs_requests(&self) -> Option<impl Iterator<Item = Tlv>>;
31}
32
33#[derive(Debug, PartialEq, Eq)]
34pub struct PutRequest<'src_file, 'dest_file, 'msgs_to_user, 'fh_ovrds, 'flow_label, 'fs_requests> {
35 pub destination_id: UnsignedByteField,
36 source_file: Option<&'src_file str>,
37 dest_file: Option<&'dest_file str>,
38 pub trans_mode: Option<TransmissionMode>,
39 pub closure_requested: Option<bool>,
40 pub seg_ctrl: Option<SegmentationControl>,
41 pub msgs_to_user: Option<&'msgs_to_user [Tlv<'msgs_to_user>]>,
42 pub fault_handler_overrides: Option<&'fh_ovrds [Tlv<'fh_ovrds>]>,
43 pub flow_label: Option<Tlv<'flow_label>>,
44 pub fs_requests: Option<&'fs_requests [Tlv<'fs_requests>]>,
45}
46
47impl<'src_file, 'dest_file, 'msgs_to_user, 'fh_ovrds, 'flow_label, 'fs_requests>
48 PutRequest<'src_file, 'dest_file, 'msgs_to_user, 'fh_ovrds, 'flow_label, 'fs_requests>
49{
50 #[allow(clippy::too_many_arguments)]
51 pub fn new(
52 destination_id: UnsignedByteField,
53 source_file: Option<&'src_file str>,
54 dest_file: Option<&'dest_file str>,
55 trans_mode: Option<TransmissionMode>,
56 closure_requested: Option<bool>,
57 seg_ctrl: Option<SegmentationControl>,
58 msgs_to_user: Option<&'msgs_to_user [Tlv<'msgs_to_user>]>,
59 fault_handler_overrides: Option<&'fh_ovrds [Tlv<'fh_ovrds>]>,
60 flow_label: Option<Tlv<'flow_label>>,
61 fs_requests: Option<&'fs_requests [Tlv<'fs_requests>]>,
62 ) -> Result<Self, FilePathTooLarge> {
63 generic_path_checks(source_file, dest_file)?;
64 Ok(Self {
65 destination_id,
66 source_file,
67 dest_file,
68 trans_mode,
69 closure_requested,
70 seg_ctrl,
71 msgs_to_user,
72 fault_handler_overrides,
73 flow_label,
74 fs_requests,
75 })
76 }
77}
78
79impl ReadablePutRequest for PutRequest<'_, '_, '_, '_, '_, '_> {
80 fn destination_id(&self) -> UnsignedByteField {
81 self.destination_id
82 }
83
84 fn source_file(&self) -> Option<&str> {
85 self.source_file
86 }
87
88 fn dest_file(&self) -> Option<&str> {
89 self.dest_file
90 }
91
92 fn trans_mode(&self) -> Option<TransmissionMode> {
93 self.trans_mode
94 }
95
96 fn closure_requested(&self) -> Option<bool> {
97 self.closure_requested
98 }
99
100 fn seg_ctrl(&self) -> Option<SegmentationControl> {
101 self.seg_ctrl
102 }
103
104 fn msgs_to_user(&self) -> Option<impl Iterator<Item = Tlv>> {
105 if let Some(msgs_to_user) = self.msgs_to_user {
106 return Some(msgs_to_user.iter().copied());
107 }
108 None
109 }
110
111 fn fault_handler_overrides(&self) -> Option<impl Iterator<Item = Tlv>> {
112 if let Some(fh_overrides) = self.fault_handler_overrides {
113 return Some(fh_overrides.iter().copied());
114 }
115 None
116 }
117
118 fn flow_label(&self) -> Option<Tlv> {
119 self.flow_label
120 }
121
122 fn fs_requests(&self) -> Option<impl Iterator<Item = Tlv>> {
123 if let Some(fs_requests) = self.msgs_to_user {
124 return Some(fs_requests.iter().copied());
125 }
126 None
127 }
128}
129
130pub fn generic_path_checks(
131 source_file: Option<&str>,
132 dest_file: Option<&str>,
133) -> Result<(), FilePathTooLarge> {
134 if let Some(src_file) = source_file {
135 if src_file.len() > u8::MAX as usize {
136 return Err(FilePathTooLarge(src_file.len()));
137 }
138 }
139 if let Some(dest_file) = dest_file {
140 if dest_file.len() > u8::MAX as usize {
141 return Err(FilePathTooLarge(dest_file.len()));
142 }
143 }
144 Ok(())
145}
146
147impl<'src_file, 'dest_file> PutRequest<'src_file, 'dest_file, 'static, 'static, 'static, 'static> {
148 pub fn new_regular_request(
149 dest_id: UnsignedByteField,
150 source_file: &'src_file str,
151 dest_file: &'dest_file str,
152 trans_mode: Option<TransmissionMode>,
153 closure_requested: Option<bool>,
154 ) -> Result<Self, FilePathTooLarge> {
155 generic_path_checks(Some(source_file), Some(dest_file))?;
156 Ok(Self {
157 destination_id: dest_id,
158 source_file: Some(source_file),
159 dest_file: Some(dest_file),
160 trans_mode,
161 closure_requested,
162 seg_ctrl: None,
163 msgs_to_user: None,
164 fault_handler_overrides: None,
165 flow_label: None,
166 fs_requests: None,
167 })
168 }
169}
170
171#[derive(Debug, PartialEq, Eq)]
172#[cfg_attr(feature = "defmt", derive(defmt::Format))]
173#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
174pub struct TlvWithInvalidType(pub(crate) ());
175
176impl<'msgs_to_user> PutRequest<'static, 'static, 'msgs_to_user, 'static, 'static, 'static> {
177 pub fn new_msgs_to_user_only(
178 dest_id: UnsignedByteField,
179 msgs_to_user: &'msgs_to_user [Tlv<'msgs_to_user>],
180 ) -> Result<Self, TlvWithInvalidType> {
181 Ok(Self {
182 destination_id: dest_id,
183 source_file: None,
184 dest_file: None,
185 trans_mode: None,
186 closure_requested: None,
187 seg_ctrl: None,
188 msgs_to_user: Some(msgs_to_user),
189 fault_handler_overrides: None,
190 flow_label: None,
191 fs_requests: None,
192 })
193 }
194
195 pub fn check_tlv_type_validities(&self) -> bool {
197 generic_tlv_list_type_check(self.msgs_to_user, TlvType::MsgToUser);
198 if let Some(flow_label) = &self.flow_label {
199 if flow_label.tlv_type().is_none() {
200 return false;
201 }
202 if flow_label.tlv_type().unwrap() != TlvType::FlowLabel {
203 return false;
204 }
205 }
206 generic_tlv_list_type_check(self.fault_handler_overrides, TlvType::FaultHandler);
207 generic_tlv_list_type_check(self.fs_requests, TlvType::FilestoreRequest);
208 true
209 }
210}
211
212pub fn generic_tlv_list_type_check<TlvProvider: GenericTlv>(
213 opt_tlvs: Option<&[TlvProvider]>,
214 tlv_type: TlvType,
215) -> bool {
216 if let Some(tlvs) = opt_tlvs {
217 for tlv in tlvs {
218 if tlv.tlv_type().is_none() {
219 return false;
220 }
221 if tlv.tlv_type().unwrap() != tlv_type {
222 return false;
223 }
224 }
225 }
226 true
227}
228
229#[cfg(feature = "alloc")]
230pub mod alloc_mod {
231 use core::str::Utf8Error;
232
233 use super::*;
234 use alloc::string::ToString;
235 use spacepackets::{
236 cfdp::tlv::{msg_to_user::MsgToUserTlv, ReadableTlv, TlvOwned, WritableTlv},
237 ByteConversionError,
238 };
239
240 #[derive(Debug, Clone, PartialEq, Eq)]
242 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
243 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
244 pub struct PutRequestOwned {
245 pub destination_id: UnsignedByteField,
246 source_file: Option<alloc::string::String>,
247 dest_file: Option<alloc::string::String>,
248 pub trans_mode: Option<TransmissionMode>,
249 pub closure_requested: Option<bool>,
250 pub seg_ctrl: Option<SegmentationControl>,
251 pub msgs_to_user: Option<alloc::vec::Vec<TlvOwned>>,
252 pub fault_handler_overrides: Option<alloc::vec::Vec<TlvOwned>>,
253 pub flow_label: Option<TlvOwned>,
254 pub fs_requests: Option<alloc::vec::Vec<TlvOwned>>,
255 }
256
257 impl PutRequestOwned {
258 pub fn new_regular_request(
259 dest_id: UnsignedByteField,
260 source_file: &str,
261 dest_file: &str,
262 trans_mode: Option<TransmissionMode>,
263 closure_requested: Option<bool>,
264 ) -> Result<Self, FilePathTooLarge> {
265 if source_file.len() > u8::MAX as usize {
266 return Err(FilePathTooLarge(source_file.len()));
267 }
268 if dest_file.len() > u8::MAX as usize {
269 return Err(FilePathTooLarge(dest_file.len()));
270 }
271 Ok(Self {
272 destination_id: dest_id,
273 source_file: Some(source_file.to_string()),
274 dest_file: Some(dest_file.to_string()),
275 trans_mode,
276 closure_requested,
277 seg_ctrl: None,
278 msgs_to_user: None,
279 fault_handler_overrides: None,
280 flow_label: None,
281 fs_requests: None,
282 })
283 }
284
285 pub fn new_msgs_to_user_only(
286 dest_id: UnsignedByteField,
287 msgs_to_user: &[MsgToUserTlv<'_>],
288 ) -> Result<Self, TlvWithInvalidType> {
289 Ok(Self {
290 destination_id: dest_id,
291 source_file: None,
292 dest_file: None,
293 trans_mode: None,
294 closure_requested: None,
295 seg_ctrl: None,
296 msgs_to_user: Some(msgs_to_user.iter().map(|msg| msg.tlv.to_owned()).collect()),
297 fault_handler_overrides: None,
298 flow_label: None,
299 fs_requests: None,
300 })
301 }
302
303 pub fn check_tlv_type_validities(&self) -> bool {
305 generic_tlv_list_type_check(self.msgs_to_user.as_deref(), TlvType::MsgToUser);
306 if let Some(flow_label) = &self.flow_label {
307 if flow_label.tlv_type().is_none() {
308 return false;
309 }
310 if flow_label.tlv_type().unwrap() != TlvType::FlowLabel {
311 return false;
312 }
313 }
314 generic_tlv_list_type_check(
315 self.fault_handler_overrides.as_deref(),
316 TlvType::FaultHandler,
317 );
318 generic_tlv_list_type_check(self.fs_requests.as_deref(), TlvType::FilestoreRequest);
319 true
320 }
321 }
322
323 impl From<PutRequest<'_, '_, '_, '_, '_, '_>> for PutRequestOwned {
324 fn from(req: PutRequest<'_, '_, '_, '_, '_, '_>) -> Self {
325 Self {
326 destination_id: req.destination_id,
327 source_file: req.source_file.map(|s| s.into()),
328 dest_file: req.dest_file.map(|s| s.into()),
329 trans_mode: req.trans_mode,
330 closure_requested: req.closure_requested,
331 seg_ctrl: req.seg_ctrl,
332 msgs_to_user: req
333 .msgs_to_user
334 .map(|msgs_to_user| msgs_to_user.iter().map(|msg| msg.to_owned()).collect()),
335 fault_handler_overrides: req
336 .msgs_to_user
337 .map(|fh_overides| fh_overides.iter().map(|msg| msg.to_owned()).collect()),
338 flow_label: req
339 .flow_label
340 .map(|flow_label_tlv| flow_label_tlv.to_owned()),
341 fs_requests: req
342 .fs_requests
343 .map(|fs_requests| fs_requests.iter().map(|msg| msg.to_owned()).collect()),
344 }
345 }
346 }
347
348 impl ReadablePutRequest for PutRequestOwned {
349 fn destination_id(&self) -> UnsignedByteField {
350 self.destination_id
351 }
352
353 fn source_file(&self) -> Option<&str> {
354 self.source_file.as_deref()
355 }
356
357 fn dest_file(&self) -> Option<&str> {
358 self.dest_file.as_deref()
359 }
360
361 fn trans_mode(&self) -> Option<TransmissionMode> {
362 self.trans_mode
363 }
364
365 fn closure_requested(&self) -> Option<bool> {
366 self.closure_requested
367 }
368
369 fn seg_ctrl(&self) -> Option<SegmentationControl> {
370 self.seg_ctrl
371 }
372
373 fn msgs_to_user(&self) -> Option<impl Iterator<Item = Tlv>> {
374 if let Some(msgs_to_user) = &self.msgs_to_user {
375 return Some(msgs_to_user.iter().map(|tlv_owned| tlv_owned.as_tlv()));
376 }
377 None
378 }
379
380 fn fault_handler_overrides(&self) -> Option<impl Iterator<Item = Tlv>> {
381 if let Some(fh_overrides) = &self.fault_handler_overrides {
382 return Some(fh_overrides.iter().map(|tlv_owned| tlv_owned.as_tlv()));
383 }
384 None
385 }
386
387 fn flow_label(&self) -> Option<Tlv> {
388 self.flow_label.as_ref().map(|tlv| tlv.as_tlv())
389 }
390
391 fn fs_requests(&self) -> Option<impl Iterator<Item = Tlv>> {
392 if let Some(requests) = &self.fs_requests {
393 return Some(requests.iter().map(|tlv_owned| tlv_owned.as_tlv()));
394 }
395 None
396 }
397 }
398
399 pub struct StaticPutRequestFields {
400 pub destination_id: UnsignedByteField,
401 pub source_file_buf: [u8; u8::MAX as usize],
403 pub source_file_len: usize,
405 pub dest_file_buf: [u8; u8::MAX as usize],
407 pub dest_file_len: usize,
409 pub trans_mode: Option<TransmissionMode>,
410 pub closure_requested: Option<bool>,
411 pub seg_ctrl: Option<SegmentationControl>,
412 }
413
414 impl Default for StaticPutRequestFields {
415 fn default() -> Self {
416 Self {
417 destination_id: UnsignedByteField::new(0, 0),
418 source_file_buf: [0; u8::MAX as usize],
419 source_file_len: Default::default(),
420 dest_file_buf: [0; u8::MAX as usize],
421 dest_file_len: Default::default(),
422 trans_mode: Default::default(),
423 closure_requested: Default::default(),
424 seg_ctrl: Default::default(),
425 }
426 }
427 }
428
429 impl StaticPutRequestFields {
430 pub fn clear(&mut self) {
431 self.destination_id = UnsignedByteField::new(0, 0);
432 self.source_file_len = 0;
433 self.dest_file_len = 0;
434 self.trans_mode = None;
435 self.closure_requested = None;
436 self.seg_ctrl = None;
437 }
438 }
439
440 pub struct StaticPutRequestCacher {
444 pub static_fields: StaticPutRequestFields,
445 opts_buf: alloc::vec::Vec<u8>,
446 opts_len: usize, }
448
449 impl StaticPutRequestCacher {
450 pub fn new(max_len_opts_buf: usize) -> Self {
451 Self {
452 static_fields: StaticPutRequestFields::default(),
453 opts_buf: alloc::vec![0; max_len_opts_buf],
454 opts_len: 0,
455 }
456 }
457
458 pub fn set(
459 &mut self,
460 put_request: &impl ReadablePutRequest,
461 ) -> Result<(), ByteConversionError> {
462 self.static_fields.destination_id = put_request.destination_id();
463 if let Some(source_file) = put_request.source_file() {
464 if source_file.len() > u8::MAX as usize {
465 return Err(ByteConversionError::ToSliceTooSmall {
466 found: self.static_fields.source_file_buf.len(),
467 expected: source_file.len(),
468 });
469 }
470 self.static_fields.source_file_buf[..source_file.len()]
471 .copy_from_slice(source_file.as_bytes());
472 self.static_fields.source_file_len = source_file.len();
473 }
474 if let Some(dest_file) = put_request.dest_file() {
475 if dest_file.len() > u8::MAX as usize {
476 return Err(ByteConversionError::ToSliceTooSmall {
477 found: self.static_fields.source_file_buf.len(),
478 expected: dest_file.len(),
479 });
480 }
481 self.static_fields.dest_file_buf[..dest_file.len()]
482 .copy_from_slice(dest_file.as_bytes());
483 self.static_fields.dest_file_len = dest_file.len();
484 }
485 self.static_fields.trans_mode = put_request.trans_mode();
486 self.static_fields.closure_requested = put_request.closure_requested();
487 self.static_fields.seg_ctrl = put_request.seg_ctrl();
488 let mut current_idx = 0;
489 let mut store_tlv = |tlv: &Tlv| {
490 if current_idx + tlv.len_full() > self.opts_buf.len() {
491 return Err(ByteConversionError::ToSliceTooSmall {
492 found: self.opts_buf.len(),
493 expected: current_idx + tlv.len_full(),
494 });
495 }
496 tlv.write_to_bytes(&mut self.opts_buf[current_idx..current_idx + tlv.len_full()])
498 .unwrap();
499 current_idx += tlv.len_full();
500 Ok(())
501 };
502 if let Some(fs_req) = put_request.fs_requests() {
503 for fs_req in fs_req {
504 store_tlv(&fs_req)?;
505 }
506 }
507 if let Some(msgs_to_user) = put_request.msgs_to_user() {
508 for msg_to_user in msgs_to_user {
509 store_tlv(&msg_to_user)?;
510 }
511 }
512 self.opts_len = current_idx;
513 Ok(())
514 }
515
516 pub fn has_source_file(&self) -> bool {
517 self.static_fields.source_file_len > 0
518 }
519
520 pub fn has_dest_file(&self) -> bool {
521 self.static_fields.dest_file_len > 0
522 }
523
524 pub fn source_file(&self) -> Result<&str, Utf8Error> {
525 core::str::from_utf8(
526 &self.static_fields.source_file_buf[0..self.static_fields.source_file_len],
527 )
528 }
529
530 pub fn dest_file(&self) -> Result<&str, Utf8Error> {
531 core::str::from_utf8(
532 &self.static_fields.dest_file_buf[0..self.static_fields.dest_file_len],
533 )
534 }
535
536 pub fn opts_len(&self) -> usize {
537 self.opts_len
538 }
539
540 pub fn opts_slice(&self) -> &[u8] {
541 &self.opts_buf[0..self.opts_len]
542 }
543
544 pub fn clear(&mut self) {
549 self.static_fields.clear();
550 self.opts_len = 0;
551 }
552 }
553}
554
555#[cfg(test)]
556mod tests {
557 use std::string::String;
558
559 use spacepackets::{
560 cfdp::tlv::{msg_to_user::MsgToUserTlv, ReadableTlv},
561 util::UbfU16,
562 };
563
564 use super::*;
565
566 pub const DEST_ID: UbfU16 = UbfU16::new(5);
567
568 #[test]
569 fn test_put_request_basic() {
570 let src_file = "/tmp/hello.txt";
571 let dest_file = "/tmp/hello2.txt";
572 let put_request = PutRequest::new(
573 DEST_ID.into(),
574 Some(src_file),
575 Some(dest_file),
576 None,
577 None,
578 None,
579 None,
580 None,
581 None,
582 None,
583 )
584 .unwrap();
585 let identical_request =
586 PutRequest::new_regular_request(DEST_ID.into(), src_file, dest_file, None, None)
587 .unwrap();
588 assert_eq!(put_request, identical_request);
589 }
590
591 #[test]
592 fn test_put_request_path_checks_source_too_long() {
593 let mut invalid_path = String::from("/tmp/");
594 invalid_path += "a".repeat(u8::MAX as usize).as_str();
595 let dest_file = "/tmp/hello2.txt";
596 let error =
597 PutRequest::new_regular_request(DEST_ID.into(), &invalid_path, dest_file, None, None);
598 assert!(error.is_err());
599 let error = error.unwrap_err();
600 assert_eq!(u8::MAX as usize + 5, error.0);
601 }
602
603 #[test]
604 fn test_put_request_path_checks_dest_file_too_long() {
605 let mut invalid_path = String::from("/tmp/");
606 invalid_path += "a".repeat(u8::MAX as usize).as_str();
607 let source_file = "/tmp/hello2.txt";
608 let error =
609 PutRequest::new_regular_request(DEST_ID.into(), source_file, &invalid_path, None, None);
610 assert!(error.is_err());
611 let error = error.unwrap_err();
612 assert_eq!(u8::MAX as usize + 5, error.0);
613 }
614
615 #[test]
616 fn test_owned_put_request_path_checks_source_too_long() {
617 let mut invalid_path = String::from("/tmp/");
618 invalid_path += "a".repeat(u8::MAX as usize).as_str();
619 let dest_file = "/tmp/hello2.txt";
620 let error = PutRequestOwned::new_regular_request(
621 DEST_ID.into(),
622 &invalid_path,
623 dest_file,
624 None,
625 None,
626 );
627 assert!(error.is_err());
628 let error = error.unwrap_err();
629 assert_eq!(u8::MAX as usize + 5, error.0);
630 }
631
632 #[test]
633 fn test_owned_put_request_path_checks_dest_file_too_long() {
634 let mut invalid_path = String::from("/tmp/");
635 invalid_path += "a".repeat(u8::MAX as usize).as_str();
636 let source_file = "/tmp/hello2.txt";
637 let error = PutRequestOwned::new_regular_request(
638 DEST_ID.into(),
639 source_file,
640 &invalid_path,
641 None,
642 None,
643 );
644 assert!(error.is_err());
645 let error = error.unwrap_err();
646 assert_eq!(u8::MAX as usize + 5, error.0);
647 }
648
649 #[test]
650 fn test_put_request_basic_small_ctor() {
651 let src_file = "/tmp/hello.txt";
652 let dest_file = "/tmp/hello2.txt";
653 let put_request =
654 PutRequest::new_regular_request(DEST_ID.into(), src_file, dest_file, None, None)
655 .unwrap();
656 assert_eq!(put_request.source_file(), Some(src_file));
657 assert_eq!(put_request.dest_file(), Some(dest_file));
658 assert_eq!(put_request.destination_id(), DEST_ID.into());
659 assert_eq!(put_request.seg_ctrl(), None);
660 assert_eq!(put_request.closure_requested(), None);
661 assert_eq!(put_request.trans_mode(), None);
662 assert!(put_request.fs_requests().is_none());
663 assert!(put_request.msgs_to_user().is_none());
664 assert!(put_request.fault_handler_overrides().is_none());
665 assert!(put_request.flow_label().is_none());
666 }
667
668 #[test]
669 fn test_put_request_owned_basic() {
670 let src_file = "/tmp/hello.txt";
671 let dest_file = "/tmp/hello2.txt";
672 let put_request =
673 PutRequestOwned::new_regular_request(DEST_ID.into(), src_file, dest_file, None, None)
674 .unwrap();
675 assert_eq!(put_request.source_file(), Some(src_file));
676 assert_eq!(put_request.dest_file(), Some(dest_file));
677 assert_eq!(put_request.destination_id(), DEST_ID.into());
678 assert_eq!(put_request.seg_ctrl(), None);
679 assert_eq!(put_request.closure_requested(), None);
680 assert_eq!(put_request.trans_mode(), None);
681 assert!(put_request.flow_label().is_none());
682 assert!(put_request.fs_requests().is_none());
683 assert!(put_request.msgs_to_user().is_none());
684 assert!(put_request.fault_handler_overrides().is_none());
685 assert!(put_request.flow_label().is_none());
686 let put_request_cloned = put_request.clone();
687 assert_eq!(put_request, put_request_cloned);
688 }
689
690 #[test]
691 fn test_put_request_cacher_basic() {
692 let put_request_cached = StaticPutRequestCacher::new(128);
693 assert_eq!(put_request_cached.static_fields.source_file_len, 0);
694 assert_eq!(put_request_cached.static_fields.dest_file_len, 0);
695 assert_eq!(put_request_cached.opts_len(), 0);
696 assert_eq!(put_request_cached.opts_slice(), &[]);
697 }
698
699 #[test]
700 fn test_put_request_cacher_set() {
701 let mut put_request_cached = StaticPutRequestCacher::new(128);
702 let src_file = "/tmp/hello.txt";
703 let dest_file = "/tmp/hello2.txt";
704 let put_request =
705 PutRequest::new_regular_request(DEST_ID.into(), src_file, dest_file, None, None)
706 .unwrap();
707 put_request_cached.set(&put_request).unwrap();
708 assert_eq!(
709 put_request_cached.static_fields.source_file_len,
710 src_file.len()
711 );
712 assert_eq!(
713 put_request_cached.static_fields.dest_file_len,
714 dest_file.len()
715 );
716 assert_eq!(put_request_cached.source_file().unwrap(), src_file);
717 assert_eq!(put_request_cached.dest_file().unwrap(), dest_file);
718 assert_eq!(put_request_cached.opts_len(), 0);
719 }
720
721 #[test]
722 fn test_put_request_cacher_set_and_clear() {
723 let mut put_request_cached = StaticPutRequestCacher::new(128);
724 let src_file = "/tmp/hello.txt";
725 let dest_file = "/tmp/hello2.txt";
726 let put_request =
727 PutRequest::new_regular_request(DEST_ID.into(), src_file, dest_file, None, None)
728 .unwrap();
729 put_request_cached.set(&put_request).unwrap();
730 put_request_cached.clear();
731 assert_eq!(put_request_cached.static_fields.source_file_len, 0);
732 assert_eq!(put_request_cached.static_fields.dest_file_len, 0);
733 assert_eq!(put_request_cached.opts_len(), 0);
734 }
735
736 #[test]
737 fn test_messages_to_user_ctor_owned() {
738 let msg_to_user = MsgToUserTlv::new(&[1, 2, 3]).expect("creating message to user failed");
739 let put_request = PutRequestOwned::new_msgs_to_user_only(DEST_ID.into(), &[msg_to_user])
740 .expect("creating msgs to user only put request failed");
741 let msg_to_user_iter = put_request.msgs_to_user();
742 assert!(msg_to_user_iter.is_some());
743 assert!(put_request.check_tlv_type_validities());
744 let msg_to_user_iter = msg_to_user_iter.unwrap();
745 for msg_to_user_tlv in msg_to_user_iter {
746 assert_eq!(msg_to_user_tlv.value(), msg_to_user.value());
747 assert_eq!(msg_to_user_tlv.tlv_type().unwrap(), TlvType::MsgToUser);
748 }
749 }
750
751 #[test]
752 fn test_messages_to_user_ctor() {
753 let msg_to_user = MsgToUserTlv::new(&[1, 2, 3]).expect("creating message to user failed");
754 let binding = &[msg_to_user.to_tlv()];
755 let put_request = PutRequest::new_msgs_to_user_only(DEST_ID.into(), binding)
756 .expect("creating msgs to user only put request failed");
757 let msg_to_user_iter = put_request.msgs_to_user();
758 assert!(put_request.check_tlv_type_validities());
759 assert!(msg_to_user_iter.is_some());
760 let msg_to_user_iter = msg_to_user_iter.unwrap();
761 for msg_to_user_tlv in msg_to_user_iter {
762 assert_eq!(msg_to_user_tlv.value(), msg_to_user.value());
763 assert_eq!(msg_to_user_tlv.tlv_type().unwrap(), TlvType::MsgToUser);
764 }
765 }
766
767 #[test]
768 fn test_put_request_to_owned() {
769 let src_file = "/tmp/hello.txt";
770 let dest_file = "/tmp/hello2.txt";
771 let put_request =
772 PutRequest::new_regular_request(DEST_ID.into(), src_file, dest_file, None, None)
773 .unwrap();
774 let put_request_owned: PutRequestOwned = put_request.into();
775 assert_eq!(put_request_owned.destination_id(), DEST_ID.into());
776 assert_eq!(put_request_owned.source_file().unwrap(), src_file);
777 assert_eq!(put_request_owned.dest_file().unwrap(), dest_file);
778 assert!(put_request_owned.msgs_to_user().is_none());
779 assert!(put_request_owned.trans_mode().is_none());
780 assert!(put_request_owned.closure_requested().is_none());
781 }
782}