Skip to main content

par2_rs/create/
options.rs

1use std::fmt;
2use std::path::PathBuf;
3
4use crate::types::{CancellationToken, ProgressCallback};
5
6use super::encode::ForwardKernel;
7
8/// Policy for the recovery-data creation backend.
9#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
10pub enum CreationBackend {
11    /// Use the CPU/SIMD forward encoder.
12    #[default]
13    Cpu,
14    /// Keep work below 16 GiB on CPU; at or above it, preflight native Metal
15    /// when available and use CPU when Metal cannot be admitted.
16    Auto,
17    /// Require Metal and report an actionable error when it cannot be admitted.
18    Metal,
19}
20
21/// How the creator chooses the source slice size.
22#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
23pub enum BlockSizing {
24    /// Choose a size targeting a moderate number of source slices.
25    #[default]
26    Auto,
27    /// Use an explicit source slice size in bytes.
28    Bytes(u64),
29    /// Choose a source slice size that produces no more than this many slices.
30    Count(u32),
31}
32
33/// How the creator chooses the number of recovery slices.
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub enum RecoveryAmount {
36    /// Derive recovery slices as a percentage of source slices.
37    Percent(u32),
38    /// Use an exact recovery-slice count.
39    Count(u32),
40}
41
42impl Default for RecoveryAmount {
43    fn default() -> Self {
44        Self::Percent(5)
45    }
46}
47
48/// How recovery slices are divided between recovery volume files.
49#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
50pub enum VolumeScheme {
51    /// Allocate volume sizes in powers of two, from smallest to largest.
52    #[default]
53    Variable,
54    /// Divide recovery slices as evenly as possible.
55    Uniform,
56    /// Limit each recovery volume to the number of blocks in the largest source file.
57    Limited,
58}
59
60/// Inputs and safety controls for PAR2 creation.
61///
62/// `inputs` contains explicit files only. The creator resolves their names
63/// relative to `base_path` and never walks a directory or expands a file list.
64#[derive(Clone)]
65pub struct Par2CreatorOptions {
66    /// Output path or stem. A `.par2` suffix is added when absent.
67    pub output: Option<PathBuf>,
68    /// Directory against which source names are made relative.
69    pub base_path: Option<PathBuf>,
70    /// Explicit source file paths.
71    pub inputs: Vec<PathBuf>,
72    /// Source slice-size selection.
73    pub block_sizing: BlockSizing,
74    /// Recovery-slice selection.
75    pub recovery_amount: RecoveryAmount,
76    /// Exponent assigned to the first recovery slice.
77    pub first_exponent: u32,
78    /// Recovery-volume allocation scheme.
79    pub volume_scheme: VolumeScheme,
80    /// Explicit recovery-volume count, or automatic when absent.
81    pub volume_count: Option<u32>,
82    /// Optional bounded forward-processing buffer budget in bytes.
83    pub memory_limit: Option<usize>,
84    /// Arithmetic path requested for forward recovery encoding.
85    pub forward_kernel: ForwardKernel,
86    /// Backend policy requested for recovery-data creation.
87    pub backend: CreationBackend,
88    /// Permit replacing existing output files after a successful staged write.
89    pub overwrite: bool,
90    /// Suppress filesystem writes while retaining validation and planning.
91    pub dry_run: bool,
92    /// Cooperative cancellation shared with the caller.
93    pub cancellation: CancellationToken,
94    /// Optional progress observer.
95    pub progress: Option<ProgressCallback>,
96}
97
98impl fmt::Debug for Par2CreatorOptions {
99    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
100        formatter
101            .debug_struct("Par2CreatorOptions")
102            .field("output", &self.output)
103            .field("base_path", &self.base_path)
104            .field("inputs", &self.inputs)
105            .field("block_sizing", &self.block_sizing)
106            .field("recovery_amount", &self.recovery_amount)
107            .field("first_exponent", &self.first_exponent)
108            .field("volume_scheme", &self.volume_scheme)
109            .field("volume_count", &self.volume_count)
110            .field("memory_limit", &self.memory_limit)
111            .field("forward_kernel", &self.forward_kernel)
112            .field("backend", &self.backend)
113            .field("overwrite", &self.overwrite)
114            .field("dry_run", &self.dry_run)
115            .field("cancellation", &self.cancellation.is_cancelled())
116            .field("progress", &self.progress.as_ref().map(|_| "callback"))
117            .finish()
118    }
119}
120
121impl Par2CreatorOptions {
122    /// Construct options with the default creation policy.
123    pub fn new(base_path: Option<PathBuf>, inputs: Vec<PathBuf>) -> Self {
124        Self {
125            output: None,
126            base_path,
127            inputs,
128            block_sizing: BlockSizing::Auto,
129            recovery_amount: RecoveryAmount::default(),
130            first_exponent: 0,
131            volume_scheme: VolumeScheme::default(),
132            volume_count: None,
133            memory_limit: None,
134            forward_kernel: ForwardKernel::Auto,
135            backend: CreationBackend::default(),
136            overwrite: false,
137            dry_run: false,
138            cancellation: CancellationToken::new(),
139            progress: None,
140        }
141    }
142
143    /// Construct options with an output path and explicit source files.
144    pub fn with_output(output: PathBuf, base_path: Option<PathBuf>, inputs: Vec<PathBuf>) -> Self {
145        let mut options = Self::new(base_path, inputs);
146        options.output = Some(output);
147        options
148    }
149
150    /// Set the output path or stem.
151    pub fn set_output(&mut self, output: PathBuf) {
152        self.output = Some(output);
153    }
154}
155
156impl Default for Par2CreatorOptions {
157    fn default() -> Self {
158        Self::new(None, Vec::new())
159    }
160}