1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use crate::codec::CodecError;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum MigrationError {
#[error(transparent)]
Codec(#[from] CodecError),
#[error(
"Migration chain gap for [{prefix}]: reached v{reached_version}, expected v{expected_version}"
)]
Gap {
prefix: String,
reached_version: u32,
expected_version: u32,
},
/// A step reached into a prefix whose own migration is already running, so
/// neither can go first. The whole chain is named, outermost first, ending
/// on the prefix that closed it.
#[error("a migration reached round to where it started: {}", .0.join(" -> "))]
Cycle(Vec<String>),
#[error("Migration error: {0}")]
Custom(String),
/// A step reached into a prefix that holds keys nothing records a version
/// for. There is no telling which steps have already run over them, and
/// running them again is worse than not running them at all.
#[error(
"a migration reached into [{prefix}], which holds keys nothing records a version for: \
the bookkeeping that would say which steps have run is gone"
)]
VersionUnknown { prefix: String },
/// A step reached into a line whose own migration failed earlier in the
/// same open. What it would read there is not migrated, and a value worked
/// out from it would be committed as if it were.
#[error(
"a migration reached into [{prefix}], whose own migration failed in this open: what it \
would read there is not migrated"
)]
ReachedAFailure { prefix: String },
/// What this step would record at the prefix says two things at once: two
/// declarations at one version, both owning the same place. Which of them
/// owns it is then whichever is looked at first, so the step is rolled back
/// rather than written.
#[error("[{prefix}] would be recorded saying two things at once: {said}")]
Contradiction { prefix: String, said: String },
/// Two declarations of one line at one version. Versions are told apart
/// by their number and nothing else, so this is one version said twice -
/// most often two structs sharing a prefix where each needed an `id`.
#[error(
"[{lineage}] is declared twice at version {version}, by `{}` and by `{}`: two structs \
sharing a prefix are two lines of declarations, and each needs an `id` of its own",
.between.0,
.between.1
)]
DeclaredTwice {
lineage: String,
version: u32,
between: (&'static str, &'static str),
},
/// Two lines at one prefix own one place, so what is stored there would be
/// read in whichever shape the reader met first.
#[error(
"`{at}` is owned by two lines of declarations, `{}` and `{}`: a place holds one thing, so \
one of them has to give it up",
.between.0,
.between.1
)]
ClaimedTwice {
at: String,
between: (&'static str, &'static str),
},
/// Two steps of one line take it to the same version, so running one and
/// passing over the other would decide between them by the order they were
/// handed over.
#[error(
"[{lineage}] has two steps to v{version}, `{}` and `{}`: one version is reached by one \
step",
.between.0,
.between.1
)]
StepTwice {
lineage: String,
version: u32,
between: (String, String),
},
/// A merge found one of its two sources and not the other, so it could
/// neither combine them nor leave the store as a merge of nothing leaves it.
#[error("[{prefix}] merges `{first}` and `{second}`, and only `{present}` is there")]
HalfAMerge {
prefix: String,
first: String,
second: String,
present: String,
},
/// Steps take a line past the version its struct declares, so the shape
/// they leave is one nothing declares, and a step written later for that
/// version would be passed over as already run.
#[error(
"[{lineage}] has a step to v{planned} and its struct declares v{declared}: nothing declares \
the shape that step would leave"
)]
PlanPastDeclared {
lineage: String,
planned: u32,
declared: u32,
},
/// The bookkeeping holds two records for one line, so which of them says
/// what is on disk cannot be told.
#[error("[{lineage}] is recorded twice, and which record is the shape on disk cannot be told")]
RecordedTwice { lineage: String },
#[error("Downgrade detected for [{prefix}]: DB v{db_version}, Code v{code_version}")]
Downgrade {
prefix: String,
db_version: u32,
code_version: u32,
},
}