9 Commits

10 changed files with 167 additions and 221 deletions
+1 -1
View File
@@ -29,7 +29,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@1.75.0 - uses: dtolnay/rust-toolchain@1.81.0
- run: cargo check --release - run: cargo check --release
cross-check: cross-check:
+10
View File
@@ -8,6 +8,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
# [unreleased] # [unreleased]
- Bumped `spacepackets` to v0.15
- Bumped `defmt` to v1
# [v0.2.0] 2024-11-26
- Bumped `thiserror` to v2
- Bumped `spacepackets` to v0.13
- The source and destination handlers can now be used without the `std` feature and only require
the `alloc` feature.
# [v0.1.0] 2024-09-11 # [v0.1.0] 2024-09-11
Initial release Initial release
+11 -26
View File
@@ -1,8 +1,8 @@
[package] [package]
name = "cfdp-rs" name = "cfdp-rs"
version = "0.1.0" version = "0.2.0"
edition = "2021" edition = "2021"
rust-version = "1.75.0" rust-version = "1.81.0"
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"] authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
description = "High level CCSDS File Delivery Protocol components" description = "High level CCSDS File Delivery Protocol components"
homepage = "https://egit.irs.uni-stuttgart.de/rust/cfdp" homepage = "https://egit.irs.uni-stuttgart.de/rust/cfdp"
@@ -18,33 +18,18 @@ name = "cfdp"
[dependencies] [dependencies]
crc = "3" crc = "3"
smallvec = "1" smallvec = "1"
derive-new = "0.6" derive-new = ">=0.6, <=0.7"
hashbrown = { version = ">=0.14, <=0.15", optional = true }
[dependencies.spacepackets] spacepackets = { version = "0.15", default-features = false }
version = "0.12" thiserror = { version = "2", default-features = false }
default-features = false serde = { version = "1", optional = true }
defmt = { version = "1", optional = true }
[dependencies.thiserror]
version = "1"
optional = true
[dependencies.hashbrown]
version = "0.14"
optional = true
[dependencies.serde]
version = "1"
optional = true
[dependencies.defmt]
version = "0.3"
optional = true
[features] [features]
default = ["std"] default = ["std"]
std = [ std = [
"alloc", "alloc",
"thiserror", "thiserror/std",
"spacepackets/std" "spacepackets/std"
] ]
alloc = [ alloc = [
@@ -56,9 +41,9 @@ defmt = ["dep:defmt", "spacepackets/defmt"]
[dev-dependencies] [dev-dependencies]
tempfile = "3" tempfile = "3"
rand = "0.8" rand = "0.9"
log = "0.4" log = "0.4"
fern = "0.6" fern = "0.7"
chrono = "0.4" chrono = "0.4"
clap = { version = "4", features = ["derive"] } clap = { version = "4", features = ["derive"] }
+22 -9
View File
@@ -13,23 +13,36 @@ The underlying base packet library used to generate the packets to be sent is th
# Features # Features
`cfdp-rs` currently supports following high-level features:
- Unacknowledged (class 1) file transfers for both source and destination side.
The following features have not been implemented yet. PRs or notifications for demand are welcome!
- Acknowledged (class 2) file transfers for both source and destination side.
- Suspending transfers
- Inactivity handling
- Start and end of transmission and reception opportunity handling
- Keep Alive and Prompt PDU handling
## Rust features
The goal of this library is to be flexible enough to support the use-cases of both on-board The goal of this library is to be flexible enough to support the use-cases of both on-board
software and of ground software. It has support to make integration on [std] systems as simple software and of ground software. It has support to make integration on `std` systems as simple
as possible, but also has sufficient abstraction to allow for integration on`no_std` environments. as possible, but also has sufficient abstraction to allow for integration on`no_std` environments
Currently, the handlers still require the [std] feature until and can be used on these systems as well as long as the `alloc` feature is activated.
[thiserror supports `error_in_core`](https://github.com/dtolnay/thiserror/pull/304).
It is recommended to activate the `alloc` feature at the very least to allow using the primary Please note that even though the `alloc` feature is required for the core handlers, these
components provided by this crate. These components will only allocate memory at initialization components will only allocate memory at initialization time and thus are still viable for systems
time and thus are still viable for systems where run-time allocation is prohibited. where run-time allocation is prohibited.
## Default features ### Default features
- [`std`](https://doc.rust-lang.org/std/): Enables functionality relying on the standard library. - [`std`](https://doc.rust-lang.org/std/): Enables functionality relying on the standard library.
- [`alloc`](https://doc.rust-lang.org/alloc/): Enables features which require allocation support. - [`alloc`](https://doc.rust-lang.org/alloc/): Enables features which require allocation support.
Enabled by the `std` feature. Enabled by the `std` feature.
## Optional Features ### Optional Features
- [`serde`](https://serde.rs/): Adds `serde` support for most types by adding `Serialize` and `Deserialize` `derive`s - [`serde`](https://serde.rs/): Adds `serde` support for most types by adding `Serialize` and `Deserialize` `derive`s
- [`defmt`](https://defmt.ferrous-systems.com/): Add support for the `defmt` by adding the - [`defmt`](https://defmt.ferrous-systems.com/): Add support for the `defmt` by adding the
Executable
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
export RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options"
cargo +nightly doc --all-features --open
+7 -6
View File
@@ -55,7 +55,6 @@ use spacepackets::{
}, },
util::{UnsignedByteField, UnsignedEnum}, util::{UnsignedByteField, UnsignedEnum},
}; };
use thiserror::Error;
#[derive(Debug)] #[derive(Debug)]
struct FileProperties { struct FileProperties {
@@ -93,6 +92,7 @@ struct TransferState<Countdown: CountdownProvider> {
transaction_id: Option<TransactionId>, transaction_id: Option<TransactionId>,
metadata_params: MetadataGenericParams, metadata_params: MetadataGenericParams,
progress: u64, progress: u64,
// TODO: Can we delete this for good?
// file_size_eof: u64, // file_size_eof: u64,
metadata_only: bool, metadata_only: bool,
condition_code: ConditionCode, condition_code: ConditionCode,
@@ -189,7 +189,7 @@ impl<CheckTimer: CountdownProvider> TransactionParams<CheckTimer> {
} }
} }
#[derive(Debug, Error)] #[derive(Debug, thiserror::Error)]
pub enum DestError { pub enum DestError {
/// File directive expected, but none specified /// File directive expected, but none specified
#[error("expected file directive")] #[error("expected file directive")]
@@ -215,6 +215,7 @@ pub enum DestError {
#[error("pdu error {0}")] #[error("pdu error {0}")]
Pdu(#[from] PduError), Pdu(#[from] PduError),
#[error("io error {0}")] #[error("io error {0}")]
#[cfg(feature = "std")]
Io(#[from] std::io::Error), Io(#[from] std::io::Error),
#[error("file store error {0}")] #[error("file store error {0}")]
Filestore(#[from] FilestoreError), Filestore(#[from] FilestoreError),
@@ -1429,7 +1430,7 @@ mod tests {
#[test] #[test]
fn test_segmented_file_transfer_not_acked() { fn test_segmented_file_transfer_not_acked() {
let mut rng = rand::thread_rng(); let mut rng = rand::rng();
let mut random_data = [0u8; 512]; let mut random_data = [0u8; 512];
rng.fill(&mut random_data); rng.fill(&mut random_data);
let file_size = random_data.len() as u64; let file_size = random_data.len() as u64;
@@ -1456,7 +1457,7 @@ mod tests {
#[test] #[test]
fn test_check_limit_handling_transfer_success() { fn test_check_limit_handling_transfer_success() {
let mut rng = rand::thread_rng(); let mut rng = rand::rng();
let mut random_data = [0u8; 512]; let mut random_data = [0u8; 512];
rng.fill(&mut random_data); rng.fill(&mut random_data);
let file_size = random_data.len() as u64; let file_size = random_data.len() as u64;
@@ -1502,7 +1503,7 @@ mod tests {
#[test] #[test]
fn test_check_limit_handling_limit_reached() { fn test_check_limit_handling_limit_reached() {
let mut rng = rand::thread_rng(); let mut rng = rand::rng();
let mut random_data = [0u8; 512]; let mut random_data = [0u8; 512];
rng.fill(&mut random_data); rng.fill(&mut random_data);
let file_size = random_data.len() as u64; let file_size = random_data.len() as u64;
@@ -1752,7 +1753,7 @@ mod tests {
let fault_handler = TestFaultHandler::default(); let fault_handler = TestFaultHandler::default();
let src_path = tempfile::TempPath::from_path("/tmp/test.txt").to_path_buf(); let src_path = tempfile::TempPath::from_path("/tmp/test.txt").to_path_buf();
let dest_path = tempfile::TempDir::new().unwrap(); let dest_path = tempfile::TempDir::new().unwrap();
let mut dest_path_buf = dest_path.into_path(); let mut dest_path_buf = dest_path.keep();
let mut tb = DestHandlerTestbench::new( let mut tb = DestHandlerTestbench::new(
fault_handler, fault_handler,
false, false,
+35 -99
View File
@@ -1,101 +1,35 @@
use alloc::string::{String, ToString};
use core::fmt::Display;
use spacepackets::cfdp::ChecksumType; use spacepackets::cfdp::ChecksumType;
use spacepackets::ByteConversionError; use spacepackets::ByteConversionError;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::error::Error;
use std::path::Path;
#[cfg(feature = "std")]
pub use std_mod::*; pub use std_mod::*;
#[derive(Debug, Clone)] #[derive(Debug, thiserror::Error)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(all(feature = "defmt", not(feature = "std")), derive(defmt::Format))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive] #[non_exhaustive]
pub enum FilestoreError { pub enum FilestoreError {
#[error("file does not exist")]
FileDoesNotExist, FileDoesNotExist,
#[error("file already exists")]
FileAlreadyExists, FileAlreadyExists,
#[error("directory does not exist")]
DirDoesNotExist, DirDoesNotExist,
#[error("permission error")]
Permission, Permission,
#[error("is not a file")]
IsNotFile, IsNotFile,
#[error("is not a directory")]
IsNotDirectory, IsNotDirectory,
ByteConversion(ByteConversionError), #[error("byte conversion: {0}")]
Io { ByteConversion(#[from] ByteConversionError),
raw_errno: Option<i32>, #[error("IO error: {0})")]
string: String,
},
ChecksumTypeNotImplemented(ChecksumType),
Utf8Error,
Other,
}
impl From<ByteConversionError> for FilestoreError {
fn from(value: ByteConversionError) -> Self {
Self::ByteConversion(value)
}
}
impl Display for FilestoreError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
FilestoreError::FileDoesNotExist => {
write!(f, "file does not exist")
}
FilestoreError::FileAlreadyExists => {
write!(f, "file already exists")
}
FilestoreError::DirDoesNotExist => {
write!(f, "directory does not exist")
}
FilestoreError::Permission => {
write!(f, "permission error")
}
FilestoreError::IsNotFile => {
write!(f, "is not a file")
}
FilestoreError::IsNotDirectory => {
write!(f, "is not a directory")
}
FilestoreError::ByteConversion(e) => {
write!(f, "filestore error: {e}")
}
FilestoreError::Io { raw_errno, string } => {
write!(
f,
"filestore generic IO error with raw errno {:?}: {}",
raw_errno, string
)
}
FilestoreError::ChecksumTypeNotImplemented(checksum_type) => {
write!(f, "checksum {:?} not implemented", checksum_type)
}
FilestoreError::Utf8Error => {
write!(f, "utf8 error")
}
FilestoreError::Other => {
write!(f, "some filestore error occured")
}
}
}
}
impl Error for FilestoreError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
FilestoreError::ByteConversion(e) => Some(e),
_ => None,
}
}
}
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl From<std::io::Error> for FilestoreError { Io(#[from] std::io::Error),
fn from(value: std::io::Error) -> Self { #[error("checksum type not implemented: {0:?}")]
Self::Io { ChecksumTypeNotImplemented(ChecksumType),
raw_errno: value.raw_os_error(), #[error("utf8 error")]
string: value.to_string(), Utf8Error,
} #[error("other error")]
} Other,
} }
pub trait VirtualFilestore { pub trait VirtualFilestore {
@@ -122,14 +56,7 @@ pub trait VirtualFilestore {
fn filename_from_full_path(path: &str) -> Option<&str> fn filename_from_full_path(path: &str) -> Option<&str>
where where
Self: Sized, Self: Sized;
{
// Convert the path string to a Path
let path = Path::new(path);
// Extract the file name using the file_name() method
path.file_name().and_then(|name| name.to_str())
}
fn is_file(&self, path: &str) -> Result<bool, FilestoreError>; fn is_file(&self, path: &str) -> Result<bool, FilestoreError>;
@@ -194,6 +121,7 @@ pub mod std_mod {
use std::{ use std::{
fs::{self, File, OpenOptions}, fs::{self, File, OpenOptions},
io::{BufReader, Read, Seek, SeekFrom, Write}, io::{BufReader, Read, Seek, SeekFrom, Write},
path::Path,
}; };
#[derive(Default)] #[derive(Default)]
@@ -241,10 +169,7 @@ pub mod std_mod {
} }
fn create_dir(&self, dir_path: &str) -> Result<(), FilestoreError> { fn create_dir(&self, dir_path: &str) -> Result<(), FilestoreError> {
fs::create_dir(dir_path).map_err(|e| FilestoreError::Io { fs::create_dir(dir_path)?;
raw_errno: e.raw_os_error(),
string: e.to_string(),
})?;
Ok(()) Ok(())
} }
@@ -358,6 +283,17 @@ pub mod std_mod {
_ => Err(FilestoreError::ChecksumTypeNotImplemented(checksum_type)), _ => Err(FilestoreError::ChecksumTypeNotImplemented(checksum_type)),
} }
} }
fn filename_from_full_path(path: &str) -> Option<&str>
where
Self: Sized,
{
// Convert the path string to a Path
let path = Path::new(path);
// Extract the file name using the file_name() method
path.file_name().and_then(|name| name.to_str())
}
} }
impl NativeFilestore { impl NativeFilestore {
@@ -393,7 +329,7 @@ pub mod std_mod {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::{fs, path::Path, println}; use std::{fs, path::Path, println, string::ToString};
use super::*; use super::*;
use alloc::format; use alloc::format;
@@ -706,7 +642,7 @@ mod tests {
} }
assert_eq!( assert_eq!(
error.to_string(), error.to_string(),
format!("filestore error: {}", byte_conv_error) format!("byte conversion: {}", byte_conv_error)
); );
} else { } else {
panic!("unexpected error"); panic!("unexpected error");
@@ -829,7 +765,7 @@ mod tests {
if let FilestoreError::ChecksumTypeNotImplemented(cksum_type) = error { if let FilestoreError::ChecksumTypeNotImplemented(cksum_type) = error {
assert_eq!( assert_eq!(
error.to_string(), error.to_string(),
format!("checksum {:?} not implemented", cksum_type) format!("checksum type not implemented: {:?}", cksum_type)
); );
} else { } else {
panic!("unexpected error"); panic!("unexpected error");
+34 -18
View File
@@ -1,5 +1,23 @@
//! This module contains the implementation of the CCSDS File Delivery Protocol (CFDP) high level //! # `cfdp` - High-level support for implementing CFDP
//! abstractions as specified in CCSDS 727.0-B-5. //!
//! This is a high-level support library for implementing the CCSDS File Delivery Protocol
//! according to the CCSDS 727.0-B-5 standard.
//!
//! # Features
//!
//! The crate currently supports following features:
//!
//! - Unacknowledged (class 1) file transfers for both source and destination side.
//!
//! The following features have not been implemented yet. PRs or notifications for demand are welcome!
//!
//! - Acknowledged (class 2) file transfers for both source and destination side.
//! - Suspending transfers
//! - Inactivity handling
//! - Start and end of transmission and reception opportunity handling
//! - Keep Alive and Prompt PDU handling
//!
//! # Overview
//! //!
//! The basic idea of CFDP is to convert files of any size into a stream of packets called packet //! The basic idea of CFDP is to convert files of any size into a stream of packets called packet
//! data units (PDU). CFPD has an unacknowledged and acknowledged mode, with the option to request //! data units (PDU). CFPD has an unacknowledged and acknowledged mode, with the option to request
@@ -14,11 +32,12 @@
//! The goal of this library is to be flexible enough to support the use-cases of both on-board //! The goal of this library is to be flexible enough to support the use-cases of both on-board
//! software and of ground software. It has support to make integration on [std] systems as simple //! software and of ground software. It has support to make integration on [std] systems as simple
//! as possible, but also has sufficient abstraction to allow for integration on `no_std` //! as possible, but also has sufficient abstraction to allow for integration on `no_std`
//! environments. Currently, the handlers still require the [std] feature until //! environments and can be used on these systems as well as long as the [alloc] feature is used
//! [thiserror supports `error_in_core`](https://github.com/dtolnay/thiserror/pull/304). //! as well.
//! It is recommended to activate the `alloc` feature at the very least to allow using the primary //!
//! components provided by this crate. These components will only allocate memory at initialization //! Please note even though the [alloc] feature is required for the core handlers, these components
//! time and thus are still viable for systems where run-time allocation is prohibited. //! will only allocate memory at initialization time and thus are still viable for systems where
//! run-time allocation is prohibited.
//! //!
//! The core of this library are the [crate::dest::DestinationHandler] and the //! The core of this library are the [crate::dest::DestinationHandler] and the
//! [crate::source::SourceHandler] components which model the CFDP destination and source entity //! [crate::source::SourceHandler] components which model the CFDP destination and source entity
@@ -70,12 +89,11 @@ extern crate alloc;
#[cfg(any(feature = "std", test))] #[cfg(any(feature = "std", test))]
extern crate std; extern crate std;
#[cfg(feature = "std")]
pub mod dest;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub mod dest;
pub mod filestore; pub mod filestore;
pub mod request; pub mod request;
#[cfg(feature = "std")] #[cfg(feature = "alloc")]
pub mod source; pub mod source;
pub mod time; pub mod time;
pub mod user; pub mod user;
@@ -83,8 +101,6 @@ pub mod user;
use crate::time::CountdownProvider; use crate::time::CountdownProvider;
use core::{cell::RefCell, fmt::Debug, hash::Hash}; use core::{cell::RefCell, fmt::Debug, hash::Hash};
use crc::{Crc, CRC_32_ISCSI, CRC_32_ISO_HDLC}; use crc::{Crc, CRC_32_ISCSI, CRC_32_ISO_HDLC};
#[cfg(feature = "std")]
use hashbrown::HashMap;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub use alloc_mod::*; pub use alloc_mod::*;
@@ -171,7 +187,7 @@ pub trait TimerCreatorProvider {
/// This structure models the remote entity configuration information as specified in chapter 8.3 /// This structure models the remote entity configuration information as specified in chapter 8.3
/// of the CFDP standard. /// of the CFDP standard.
///
/// Some of the fields which were not considered necessary for the Rust implementation /// Some of the fields which were not considered necessary for the Rust implementation
/// were omitted. Some other fields which are not contained inside the standard but are considered /// were omitted. Some other fields which are not contained inside the standard but are considered
/// necessary for the Rust implementation are included. /// necessary for the Rust implementation are included.
@@ -288,12 +304,12 @@ pub trait RemoteEntityConfigProvider {
fn remove_config(&mut self, remote_id: u64) -> bool; fn remove_config(&mut self, remote_id: u64) -> bool;
} }
/// This is a thin wrapper around a [HashMap] to store remote entity configurations. /// This is a thin wrapper around a [hashbrown::HashMap] to store remote entity configurations.
/// It implements the full [RemoteEntityConfigProvider] trait. /// It implements the full [RemoteEntityConfigProvider] trait.
#[cfg(feature = "std")] #[cfg(feature = "alloc")]
#[derive(Default, Debug)] #[derive(Default, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct StdRemoteEntityConfigProvider(pub HashMap<u64, RemoteEntityConfig>); pub struct StdRemoteEntityConfigProvider(pub hashbrown::HashMap<u64, RemoteEntityConfig>);
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl RemoteEntityConfigProvider for StdRemoteEntityConfigProvider { impl RemoteEntityConfigProvider for StdRemoteEntityConfigProvider {
@@ -879,7 +895,7 @@ impl<'raw> PduRawWithInfo<'raw> {
}); });
} }
if pdu_header.pdu_datafield_len() < 1 { if pdu_header.pdu_datafield_len() < 1 {
return Err(PduError::FormatError); return Err(PduError::Format);
} }
// Route depending on PDU type and directive type if applicable. Retrieve directive type // Route depending on PDU type and directive type if applicable. Retrieve directive type
// from the raw stream for better performance (with sanity and directive code check). // from the raw stream for better performance (with sanity and directive code check).
@@ -1548,7 +1564,7 @@ pub(crate) mod tests {
#[test] #[test]
fn transaction_id_hashable_usable_as_map_key() { fn transaction_id_hashable_usable_as_map_key() {
let mut map = HashMap::new(); let mut map = hashbrown::HashMap::new();
let transaction_id_0 = TransactionId::new( let transaction_id_0 = TransactionId::new(
UnsignedByteFieldU8::new(1).into(), UnsignedByteFieldU8::new(1).into(),
UnsignedByteFieldU8::new(2).into(), UnsignedByteFieldU8::new(2).into(),
+12 -12
View File
@@ -24,10 +24,10 @@ pub trait ReadablePutRequest {
fn closure_requested(&self) -> Option<bool>; fn closure_requested(&self) -> Option<bool>;
fn seg_ctrl(&self) -> Option<SegmentationControl>; fn seg_ctrl(&self) -> Option<SegmentationControl>;
fn msgs_to_user(&self) -> Option<impl Iterator<Item = Tlv>>; fn msgs_to_user(&self) -> Option<impl Iterator<Item = Tlv<'_>>>;
fn fault_handler_overrides(&self) -> Option<impl Iterator<Item = Tlv>>; fn fault_handler_overrides(&self) -> Option<impl Iterator<Item = Tlv<'_>>>;
fn flow_label(&self) -> Option<Tlv>; fn flow_label(&self) -> Option<Tlv<'_>>;
fn fs_requests(&self) -> Option<impl Iterator<Item = Tlv>>; fn fs_requests(&self) -> Option<impl Iterator<Item = Tlv<'_>>>;
} }
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
@@ -101,25 +101,25 @@ impl ReadablePutRequest for PutRequest<'_, '_, '_, '_, '_, '_> {
self.seg_ctrl self.seg_ctrl
} }
fn msgs_to_user(&self) -> Option<impl Iterator<Item = Tlv>> { fn msgs_to_user(&self) -> Option<impl Iterator<Item = Tlv<'_>>> {
if let Some(msgs_to_user) = self.msgs_to_user { if let Some(msgs_to_user) = self.msgs_to_user {
return Some(msgs_to_user.iter().copied()); return Some(msgs_to_user.iter().copied());
} }
None None
} }
fn fault_handler_overrides(&self) -> Option<impl Iterator<Item = Tlv>> { fn fault_handler_overrides(&self) -> Option<impl Iterator<Item = Tlv<'_>>> {
if let Some(fh_overrides) = self.fault_handler_overrides { if let Some(fh_overrides) = self.fault_handler_overrides {
return Some(fh_overrides.iter().copied()); return Some(fh_overrides.iter().copied());
} }
None None
} }
fn flow_label(&self) -> Option<Tlv> { fn flow_label(&self) -> Option<Tlv<'_>> {
self.flow_label self.flow_label
} }
fn fs_requests(&self) -> Option<impl Iterator<Item = Tlv>> { fn fs_requests(&self) -> Option<impl Iterator<Item = Tlv<'_>>> {
if let Some(fs_requests) = self.msgs_to_user { if let Some(fs_requests) = self.msgs_to_user {
return Some(fs_requests.iter().copied()); return Some(fs_requests.iter().copied());
} }
@@ -370,25 +370,25 @@ pub mod alloc_mod {
self.seg_ctrl self.seg_ctrl
} }
fn msgs_to_user(&self) -> Option<impl Iterator<Item = Tlv>> { fn msgs_to_user(&self) -> Option<impl Iterator<Item = Tlv<'_>>> {
if let Some(msgs_to_user) = &self.msgs_to_user { if let Some(msgs_to_user) = &self.msgs_to_user {
return Some(msgs_to_user.iter().map(|tlv_owned| tlv_owned.as_tlv())); return Some(msgs_to_user.iter().map(|tlv_owned| tlv_owned.as_tlv()));
} }
None None
} }
fn fault_handler_overrides(&self) -> Option<impl Iterator<Item = Tlv>> { fn fault_handler_overrides(&self) -> Option<impl Iterator<Item = Tlv<'_>>> {
if let Some(fh_overrides) = &self.fault_handler_overrides { if let Some(fh_overrides) = &self.fault_handler_overrides {
return Some(fh_overrides.iter().map(|tlv_owned| tlv_owned.as_tlv())); return Some(fh_overrides.iter().map(|tlv_owned| tlv_owned.as_tlv()));
} }
None None
} }
fn flow_label(&self) -> Option<Tlv> { fn flow_label(&self) -> Option<Tlv<'_>> {
self.flow_label.as_ref().map(|tlv| tlv.as_tlv()) self.flow_label.as_ref().map(|tlv| tlv.as_tlv())
} }
fn fs_requests(&self) -> Option<impl Iterator<Item = Tlv>> { fn fs_requests(&self) -> Option<impl Iterator<Item = Tlv<'_>>> {
if let Some(requests) = &self.fs_requests { if let Some(requests) = &self.fs_requests {
return Some(requests.iter().map(|tlv_owned| tlv_owned.as_tlv())); return Some(requests.iter().map(|tlv_owned| tlv_owned.as_tlv()));
} }
+6 -24
View File
@@ -386,7 +386,7 @@ impl<
/// This function is used to pass a put request to the source handler, which is /// This function is used to pass a put request to the source handler, which is
/// also used to start a file copy operation. As such, this function models the Put.request /// also used to start a file copy operation. As such, this function models the Put.request
/// CFDP primtiive. /// CFDP primtiive.
///
/// Please note that the source handler can also process one put request at a time. /// Please note that the source handler can also process one put request at a time.
/// The caller is responsible of creating a new source handler, one handler can only handle /// The caller is responsible of creating a new source handler, one handler can only handle
/// one file copy request at a time. /// one file copy request at a time.
@@ -505,7 +505,8 @@ impl<
} }
if let Some(active_id) = self.transaction_id() { if let Some(active_id) = self.transaction_id() {
if active_id == *transaction_id { if active_id == *transaction_id {
self.notice_of_cancellation(user, ConditionCode::CancelRequestReceived)?; // Control flow result can be ignored here for the cancel request.
let _ = self.notice_of_cancellation(user, ConditionCode::CancelRequestReceived)?;
return Ok(true); return Ok(true);
} }
} }
@@ -748,25 +749,6 @@ impl<
} }
fn notice_of_completion(&mut self, cfdp_user: &mut impl CfdpUser) { fn notice_of_completion(&mut self, cfdp_user: &mut impl CfdpUser) {
/*
def _notice_of_completion(self):
if self.cfg.indication_cfg.transaction_finished_indication_required:
assert self._params.transaction_id is not None
# This happens for unacknowledged file copy operation with no closure.
if self._params.finished_params is None:
self._params.finished_params = FinishedParams(
condition_code=ConditionCode.NO_ERROR,
delivery_code=DeliveryCode.DATA_COMPLETE,
file_status=FileStatus.FILE_STATUS_UNREPORTED,
)
indication_params = TransactionFinishedParams(
transaction_id=self._params.transaction_id,
finished_params=self._params.finished_params,
)
self.user.transaction_finished_indication(indication_params)
# Transaction finished
self.reset()
*/
let tstate = self.tstate.as_ref().unwrap(); let tstate = self.tstate.as_ref().unwrap();
if self.local_cfg.indication_cfg.transaction_finished { if self.local_cfg.indication_cfg.transaction_finished {
// The first case happens for unacknowledged file copy operation with no closure. // The first case happens for unacknowledged file copy operation with no closure.
@@ -1552,7 +1534,7 @@ mod tests {
.open(&tb.srcfile) .open(&tb.srcfile)
.expect("opening file failed"); .expect("opening file failed");
let mut rand_data = [0u8; 140]; let mut rand_data = [0u8; 140];
rand::thread_rng().fill(&mut rand_data[..]); rand::rng().fill(&mut rand_data[..]);
file.write_all(&rand_data) file.write_all(&rand_data)
.expect("writing file content failed"); .expect("writing file content failed");
drop(file); drop(file);
@@ -1571,7 +1553,7 @@ mod tests {
.open(&tb.srcfile) .open(&tb.srcfile)
.expect("opening file failed"); .expect("opening file failed");
let mut rand_data = [0u8; 140]; let mut rand_data = [0u8; 140];
rand::thread_rng().fill(&mut rand_data[..]); rand::rng().fill(&mut rand_data[..]);
file.write_all(&rand_data) file.write_all(&rand_data)
.expect("writing file content failed"); .expect("writing file content failed");
drop(file); drop(file);
@@ -1767,7 +1749,7 @@ mod tests {
.open(&tb.srcfile) .open(&tb.srcfile)
.expect("opening file failed"); .expect("opening file failed");
let mut rand_data = [0u8; 140]; let mut rand_data = [0u8; 140];
rand::thread_rng().fill(&mut rand_data[..]); rand::rng().fill(&mut rand_data[..]);
file.write_all(&rand_data) file.write_all(&rand_data)
.expect("writing file content failed"); .expect("writing file content failed");
drop(file); drop(file);