dropshot_api_manager_types/
validation.rs1use crate::{ManagedApiMetadata, Versions};
4use camino::Utf8PathBuf;
5use std::{fmt, ops::Deref};
6
7pub struct ValidationContext<'a> {
9 backend: &'a mut dyn ValidationBackend,
10}
11
12impl<'a> ValidationContext<'a> {
13 #[doc(hidden)]
15 pub fn new(backend: &'a mut dyn ValidationBackend) -> Self {
16 Self { backend }
17 }
18
19 pub fn ident(&self) -> &ApiIdent {
24 self.backend.ident()
25 }
26
27 pub fn file_name(&self) -> &ApiSpecFileName {
32 self.backend.file_name()
33 }
34
35 pub fn is_latest(&self) -> bool {
42 self.backend.is_latest()
43 }
44
45 pub fn is_blessed(&self) -> Option<bool> {
48 self.backend.is_blessed()
49 }
50
51 pub fn versions(&self) -> &Versions {
53 self.backend.versions()
54 }
55
56 pub fn title(&self) -> &str {
58 self.backend.title()
59 }
60
61 pub fn metadata(&self) -> &ManagedApiMetadata {
63 self.backend.metadata()
64 }
65
66 pub fn report_error(&mut self, error: anyhow::Error) {
68 self.backend.report_error(error);
69 }
70
71 pub fn record_file_contents(
79 &mut self,
80 path: impl Into<Utf8PathBuf>,
81 contents: Vec<u8>,
82 ) {
83 self.backend.record_file_contents(path.into(), contents);
84 }
85}
86
87#[doc(hidden)]
91pub trait ValidationBackend {
92 fn ident(&self) -> &ApiIdent;
93 fn file_name(&self) -> &ApiSpecFileName;
94 fn versions(&self) -> &Versions;
95 fn is_latest(&self) -> bool;
96 fn is_blessed(&self) -> Option<bool>;
97 fn title(&self) -> &str;
98 fn metadata(&self) -> &ManagedApiMetadata;
99 fn report_error(&mut self, error: anyhow::Error);
100 fn record_file_contents(&mut self, path: Utf8PathBuf, contents: Vec<u8>);
101}
102
103#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
106pub struct ApiSpecFileName {
107 ident: ApiIdent,
108 kind: ApiSpecFileNameKind,
109}
110
111impl fmt::Display for ApiSpecFileName {
112 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113 f.write_str(self.path().as_str())
114 }
115}
116
117impl ApiSpecFileName {
118 #[doc(hidden)]
120 pub fn new(ident: ApiIdent, kind: ApiSpecFileNameKind) -> ApiSpecFileName {
121 ApiSpecFileName { ident, kind }
122 }
123
124 pub fn ident(&self) -> &ApiIdent {
125 &self.ident
126 }
127
128 pub fn kind(&self) -> &ApiSpecFileNameKind {
129 &self.kind
130 }
131
132 pub fn path(&self) -> Utf8PathBuf {
135 match &self.kind {
136 ApiSpecFileNameKind::Lockstep => {
137 Utf8PathBuf::from_iter([self.basename()])
138 }
139 ApiSpecFileNameKind::Versioned { .. } => Utf8PathBuf::from_iter([
140 self.ident.deref().clone(),
141 self.basename(),
142 ]),
143 }
144 }
145
146 pub fn basename(&self) -> String {
148 match &self.kind {
149 ApiSpecFileNameKind::Lockstep => format!("{}.json", self.ident),
150 ApiSpecFileNameKind::Versioned { version, hash } => {
151 format!("{}-{}-{}.json", self.ident, version, hash)
152 }
153 }
154 }
155
156 pub fn version(&self) -> Option<&semver::Version> {
158 match &self.kind {
159 ApiSpecFileNameKind::Lockstep => None,
160 ApiSpecFileNameKind::Versioned { version, .. } => Some(version),
161 }
162 }
163
164 pub fn hash(&self) -> Option<&str> {
166 match &self.kind {
167 ApiSpecFileNameKind::Lockstep => None,
168 ApiSpecFileNameKind::Versioned { hash, .. } => Some(hash),
169 }
170 }
171}
172
173#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
175pub enum ApiSpecFileNameKind {
176 Lockstep,
178 Versioned {
180 version: semver::Version,
182 hash: String,
184 },
185}
186
187#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
189pub struct ApiIdent(String);
190
191impl fmt::Debug for ApiIdent {
192 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
193 self.0.fmt(f)
194 }
195}
196
197impl Deref for ApiIdent {
198 type Target = String;
199
200 fn deref(&self) -> &Self::Target {
201 &self.0
202 }
203}
204
205impl fmt::Display for ApiIdent {
206 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207 self.0.fmt(f)
208 }
209}
210
211impl<S: Into<String>> From<S> for ApiIdent {
212 fn from(value: S) -> Self {
213 Self(value.into())
214 }
215}
216
217impl ApiIdent {
218 pub fn versioned_api_latest_symlink(&self) -> String {
220 format!("{self}-latest.json")
221 }
222
223 pub fn versioned_api_is_latest_symlink(&self, base_name: &str) -> bool {
226 base_name == self.versioned_api_latest_symlink()
227 }
228}