@@ -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 ) ]
434508pub 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