Skip to main content

xianyun_core/config/
versions.rs

1//! Port of `internal/config/versions`: the contract for versioned Caproni
2//! configurations that can upgrade themselves toward the latest schema
3//! version.
4
5use thiserror::Error;
6
7#[derive(Debug, Error)]
8pub enum UpgraderError {
9    #[error("upgrade step failed: {0}")]
10    Step(String),
11}
12
13/// A versioned config that upgrades itself one step toward the latest schema
14/// version. The latest version's `upgrade` is a no-op that returns the
15/// receiver unchanged, which is how the upgrade walker detects completion.
16///
17/// Unlike the Go `Upgrade(log *slog.Logger) (Upgrader, error)`, which can
18/// return the exact same pointer to signal termination, Rust's ownership
19/// rules make returning "the same object" from `&self` awkward with a
20/// `Box<dyn Upgrader>` return type. The real implementation will need to
21/// settle this (e.g. via an enum of known versions, or an `is_terminal()`
22/// query) rather than pointer identity; see `PORT_NOTES.md`.
23pub trait Upgrader {
24    fn upgrade(&self) -> Result<Box<dyn Upgrader>, UpgraderError>;
25
26    /// Reports whether this value is already at the latest version, i.e.
27    /// whether `upgrade` would be a no-op. This is the termination signal
28    /// `config::registry::walk` uses instead of the Go original's
29    /// pointer-identity check (`next == cfg`): Rust's `Box<dyn Upgrader>`
30    /// return type has no equivalent "return the same object" signal, so the
31    /// walker asks each value directly rather than comparing addresses.
32    /// Defaults to `false`; only the latest version's `Upgrader` impl
33    /// overrides it.
34    fn is_terminal(&self) -> bool {
35        false
36    }
37
38    /// Exposes `self` as `&dyn Any`, so a caller holding a `Box<dyn
39    /// Upgrader>` at the end of an upgrade walk can downcast back to the
40    /// concrete type it expects — the Rust equivalent of the Go original's
41    /// `upgraded.(*latest.CaproniConfig)` type assertion, since Rust trait
42    /// objects need an explicit escape hatch (there is no built-in upcast
43    /// from `dyn Upgrader` to `dyn Any` without this).
44    fn as_any(&self) -> &dyn std::any::Any;
45}