Skip to content

Commit 5e556de

Browse files
committed
📝 Expand documentation comment for WriteOptions
1 parent 762b529 commit 5e556de

1 file changed

Lines changed: 101 additions & 3 deletions

File tree

lib/src/entry/options.rs

Lines changed: 101 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,81 @@ impl TryFrom<u8> for DataKind {
429429
}
430430
}
431431

432-
/// Options for writing an entry.
432+
/// Options for writing entries to a PNA archive.
433+
///
434+
/// This type configures compression, encryption, and password hashing for archive entries.
435+
/// Options are created using the builder pattern via [`WriteOptions::builder()`] or by
436+
/// using the convenience constructor [`WriteOptions::store()`] for uncompressed entries.
437+
///
438+
/// # Compression and Encryption Order
439+
///
440+
/// When both compression and encryption are enabled, data is **compressed first, then encrypted**.
441+
/// This order maximizes compression efficiency since encrypted data is essentially random
442+
/// and cannot be compressed effectively.
443+
///
444+
/// Data flow: `Original → Compress → Encrypt → Write to archive`
445+
///
446+
/// # Security Considerations
447+
///
448+
/// - **Hash Algorithm**: Always use [`HashAlgorithm::argon2id()`] in production for password-based
449+
/// encryption. [`HashAlgorithm::pbkdf2_sha256()`] is primarily for compatibility with older
450+
/// systems or when Argon2 is not available.
451+
/// - **Cipher Mode**: CTR mode ([`CipherMode::CTR`]) is recommended over CBC for most use cases
452+
/// as it allows parallel processing and has simpler security requirements.
453+
/// - **IV Generation**: Initialization vectors (IVs) are automatically generated using
454+
/// cryptographically secure random number generation. You do not need to provide IVs.
455+
/// - **Password Strength**: Use strong passwords (12+ characters, mixed case, numbers, symbols)
456+
/// as the encryption key is derived from the password.
457+
///
458+
/// # Examples
459+
///
460+
/// Store without compression or encryption:
461+
/// ```rust
462+
/// use libpna::WriteOptions;
463+
///
464+
/// let opts = WriteOptions::store();
465+
/// ```
466+
///
467+
/// Compress only (no encryption):
468+
/// ```rust
469+
/// use libpna::{WriteOptions, Compression, CompressionLevel};
470+
///
471+
/// let opts = WriteOptions::builder()
472+
/// .compression(Compression::ZStandard)
473+
/// .compression_level(CompressionLevel::max())
474+
/// .build();
475+
/// ```
476+
///
477+
/// Encrypt only (no compression):
478+
/// ```rust
479+
/// use libpna::{WriteOptions, Encryption, CipherMode, HashAlgorithm};
480+
///
481+
/// let opts = WriteOptions::builder()
482+
/// .encryption(Encryption::Aes)
483+
/// .cipher_mode(CipherMode::CTR)
484+
/// .hash_algorithm(HashAlgorithm::argon2id())
485+
/// .password(Some("secure_password"))
486+
/// .build();
487+
/// ```
488+
///
489+
/// Both compression and encryption (recommended for sensitive data):
490+
/// ```rust
491+
/// use libpna::{WriteOptions, Compression, Encryption, CipherMode, HashAlgorithm};
492+
///
493+
/// let opts = WriteOptions::builder()
494+
/// .compression(Compression::ZStandard)
495+
/// .encryption(Encryption::Aes)
496+
/// .cipher_mode(CipherMode::CTR)
497+
/// .hash_algorithm(HashAlgorithm::argon2id())
498+
/// .password(Some("secure_password"))
499+
/// .build();
500+
/// ```
501+
///
502+
/// # Relationship to ReadOptions
503+
///
504+
/// When reading an archive, use [`ReadOptions`] to provide the password for decryption.
505+
/// The compression algorithm and cipher mode are stored in the archive metadata, so you
506+
/// only need to provide the password.
433507
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
434508
pub struct WriteOptions {
435509
compress: Compress,
@@ -587,9 +661,33 @@ impl WriteOptionsBuilder {
587661

588662
/// Creates a new [`WriteOptions`] from this builder.
589663
///
590-
/// ## Panics
664+
/// This finalizes the builder configuration and creates an immutable [`WriteOptions`]
665+
/// that can be used when creating entries.
591666
///
592-
/// Panic will occur when encryption is enabled and a password is not provided.
667+
/// # Panics
668+
///
669+
/// Panics if [`encryption()`](Self::encryption) was set to [`Encryption::Aes`] or
670+
/// [`Encryption::Camellia`] but [`password()`](Self::password) was not called with
671+
/// a password.
672+
///
673+
/// **Always provide a password when enabling encryption.** The following code will panic:
674+
/// ```no_run
675+
/// use libpna::{WriteOptions, Encryption};
676+
///
677+
/// let opts = WriteOptions::builder()
678+
/// .encryption(Encryption::Aes)
679+
/// .build(); // PANICS: Password was not provided.
680+
/// ```
681+
///
682+
/// **Correct usage:**
683+
/// ```rust
684+
/// use libpna::{WriteOptions, Encryption};
685+
///
686+
/// let opts = WriteOptions::builder()
687+
/// .encryption(Encryption::Aes)
688+
/// .password(Some("secure_password"))
689+
/// .build(); // OK
690+
/// ```
593691
#[inline]
594692
pub fn build(&self) -> WriteOptions {
595693
let cipher = if self.encryption != Encryption::No {

0 commit comments

Comments
 (0)