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 {
29 self.backend.file_name()
30 }
31
32 pub fn versions(&self) -> &Versions {
34 self.backend.versions()
35 }
36
37 pub fn title(&self) -> &str {
39 self.backend.title()
40 }
41
42 pub fn metadata(&self) -> &ManagedApiMetadata {
44 self.backend.metadata()
45 }
46
47 pub fn report_error(&mut self, error: anyhow::Error) {
49 self.backend.report_error(error);
50 }
51
52 pub fn record_file_contents(
60 &mut self,
61 path: impl Into<Utf8PathBuf>,
62 contents: Vec<u8>,
63 ) {
64 self.backend.record_file_contents(path.into(), contents);
65 }
66}
67
68#[doc(hidden)]
72pub trait ValidationBackend {
73 fn ident(&self) -> &ApiIdent;
74 fn file_name(&self) -> &ApiSpecFileName;
75 fn versions(&self) -> &Versions;
76 fn title(&self) -> &str;
77 fn metadata(&self) -> &ManagedApiMetadata;
78 fn report_error(&mut self, error: anyhow::Error);
79 fn record_file_contents(&mut self, path: Utf8PathBuf, contents: Vec<u8>);
80}
81
82#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
85pub struct ApiSpecFileName {
86 ident: ApiIdent,
87 kind: ApiSpecFileNameKind,
88}
89
90impl fmt::Display for ApiSpecFileName {
91 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92 f.write_str(self.path().as_str())
93 }
94}
95
96impl ApiSpecFileName {
97 #[doc(hidden)]
99 pub fn new(ident: ApiIdent, kind: ApiSpecFileNameKind) -> ApiSpecFileName {
100 ApiSpecFileName { ident, kind }
101 }
102
103 pub fn ident(&self) -> &ApiIdent {
104 &self.ident
105 }
106
107 pub fn kind(&self) -> &ApiSpecFileNameKind {
108 &self.kind
109 }
110
111 pub fn path(&self) -> Utf8PathBuf {
114 match &self.kind {
115 ApiSpecFileNameKind::Lockstep => {
116 Utf8PathBuf::from_iter([self.basename()])
117 }
118 ApiSpecFileNameKind::Versioned { .. } => Utf8PathBuf::from_iter([
119 self.ident.deref().clone(),
120 self.basename(),
121 ]),
122 }
123 }
124
125 pub fn basename(&self) -> String {
127 match &self.kind {
128 ApiSpecFileNameKind::Lockstep => format!("{}.json", self.ident),
129 ApiSpecFileNameKind::Versioned { version, hash } => {
130 format!("{}-{}-{}.json", self.ident, version, hash)
131 }
132 }
133 }
134
135 pub fn version(&self) -> Option<&semver::Version> {
137 match &self.kind {
138 ApiSpecFileNameKind::Lockstep => None,
139 ApiSpecFileNameKind::Versioned { version, .. } => Some(version),
140 }
141 }
142
143 pub fn hash(&self) -> Option<&str> {
145 match &self.kind {
146 ApiSpecFileNameKind::Lockstep => None,
147 ApiSpecFileNameKind::Versioned { hash, .. } => Some(hash),
148 }
149 }
150}
151
152#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
154pub enum ApiSpecFileNameKind {
155 Lockstep,
157 Versioned {
159 version: semver::Version,
161 hash: String,
163 },
164}
165
166#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
168pub struct ApiIdent(String);
169
170impl fmt::Debug for ApiIdent {
171 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
172 self.0.fmt(f)
173 }
174}
175
176impl Deref for ApiIdent {
177 type Target = String;
178
179 fn deref(&self) -> &Self::Target {
180 &self.0
181 }
182}
183
184impl fmt::Display for ApiIdent {
185 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186 self.0.fmt(f)
187 }
188}
189
190impl<S: Into<String>> From<S> for ApiIdent {
191 fn from(value: S) -> Self {
192 Self(value.into())
193 }
194}
195
196impl ApiIdent {
197 pub fn versioned_api_latest_symlink(&self) -> String {
199 format!("{self}-latest.json")
200 }
201
202 pub fn versioned_api_is_latest_symlink(&self, base_name: &str) -> bool {
205 base_name == self.versioned_api_latest_symlink()
206 }
207}