rtb_update/options.rs
1//! Value types that flow into and out of [`crate::Updater`].
2
3use std::sync::Arc;
4
5/// Outcome of an [`Updater::check`](crate::Updater::check) call. Cheap
6/// — no asset downloads.
7#[derive(Debug, Clone)]
8#[non_exhaustive]
9pub enum CheckOutcome {
10 /// The installed version is already at the latest available.
11 UpToDate {
12 /// The installed version.
13 current: semver::Version,
14 },
15 /// A newer release is available.
16 Newer {
17 /// The installed version.
18 current: semver::Version,
19 /// The newer version discovered upstream.
20 latest: semver::Version,
21 /// Full release metadata — pass to `run()` if you want to skip
22 /// re-fetching it.
23 release: rtb_forge::Release,
24 },
25 /// Installed version is newer than anything the upstream provider
26 /// surfaces. Typically a tool-author misconfiguration; the updater
27 /// never auto-downgrades — callers inspect and decide.
28 Older {
29 /// The installed version.
30 current: semver::Version,
31 /// The latest version upstream reports.
32 latest: semver::Version,
33 },
34}
35
36/// Options controlling a single [`Updater::run`](crate::Updater::run).
37///
38/// Construct via `RunOptions::default()` + field mutation, or via a
39/// struct literal with field update syntax. Not `#[non_exhaustive]` —
40/// adding a field is treated as a breaking change (it is), so callers
41/// retain full struct-literal access. Adding fields requires a minor
42/// bump per the pre-1.0 API-stability policy (framework spec
43/// § API Stability).
44#[derive(Clone, Default)]
45pub struct RunOptions {
46 /// Re-install even when the current version already matches. Used
47 /// to repair a corrupted binary.
48 pub force: bool,
49 /// Target a specific version instead of "latest". Downgrades
50 /// require `force = true`.
51 pub target: Option<semver::Version>,
52 /// Include prereleases when selecting "latest".
53 pub include_prereleases: bool,
54 /// Progress callback. `None` means silent.
55 pub progress: Option<ProgressSink>,
56 /// Verify + stage the binary but do not swap. Leaves the staged
57 /// binary in the cache dir for inspection.
58 pub dry_run: bool,
59}
60
61impl std::fmt::Debug for RunOptions {
62 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63 f.debug_struct("RunOptions")
64 .field("force", &self.force)
65 .field("target", &self.target)
66 .field("include_prereleases", &self.include_prereleases)
67 .field("progress", &self.progress.as_ref().map(|_| "<callback>"))
68 .field("dry_run", &self.dry_run)
69 .finish()
70 }
71}
72
73/// Outcome of a successful [`Updater::run`](crate::Updater::run).
74#[derive(Debug, Clone, serde::Serialize)]
75#[non_exhaustive]
76pub struct RunOutcome {
77 /// Version before the run.
78 #[serde(serialize_with = "serialize_version")]
79 pub from_version: semver::Version,
80 /// Version after the run (or target, if dry-run).
81 #[serde(serialize_with = "serialize_version")]
82 pub to_version: semver::Version,
83 /// Bytes downloaded for the asset.
84 pub bytes: u64,
85 /// `false` when `RunOptions::dry_run` was set.
86 pub swapped: bool,
87 /// Where the staged binary lives on disk — `Some` only for dry-runs.
88 pub staged_at: Option<std::path::PathBuf>,
89}
90
91fn serialize_version<S: serde::Serializer>(
92 v: &semver::Version,
93 s: S,
94) -> std::result::Result<S::Ok, S::Error> {
95 s.collect_str(v)
96}
97
98/// Progress event emitted during a [`Updater::run`](crate::Updater::run).
99#[derive(Debug, Clone)]
100#[non_exhaustive]
101pub enum ProgressEvent {
102 /// The updater has started a version check.
103 Checking,
104 /// Bytes have been received from the provider's asset stream.
105 Downloading {
106 /// Bytes written to the staged file so far.
107 bytes_done: u64,
108 /// Content-length the provider reported (or `0` if unknown).
109 bytes_total: u64,
110 },
111 /// Signature + checksum verification is in progress.
112 Verifying,
113 /// The self-test subprocess is being invoked on the staged binary.
114 SelfTesting,
115 /// `self-replace` is about to run.
116 Swapping,
117 /// The flow completed successfully.
118 Done {
119 /// Version now on disk (and about to replace the running process
120 /// on its next invocation).
121 version: semver::Version,
122 },
123}
124
125/// Cloneable boxed callback. Pass `None` in [`RunOptions::progress`]
126/// for silent runs.
127pub type ProgressSink = Arc<dyn Fn(ProgressEvent) + Send + Sync + 'static>;