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 hash(&self) -> Option<&str> {
137 match &self.kind {
138 ApiSpecFileNameKind::Lockstep => None,
139 ApiSpecFileNameKind::Versioned { hash, .. } => Some(hash),
140 }
141 }
142}
143
144#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
146pub enum ApiSpecFileNameKind {
147 Lockstep,
149 Versioned {
151 version: semver::Version,
153 hash: String,
155 },
156}
157
158#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
160pub struct ApiIdent(String);
161
162impl fmt::Debug for ApiIdent {
163 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164 self.0.fmt(f)
165 }
166}
167
168impl Deref for ApiIdent {
169 type Target = String;
170
171 fn deref(&self) -> &Self::Target {
172 &self.0
173 }
174}
175
176impl fmt::Display for ApiIdent {
177 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178 self.0.fmt(f)
179 }
180}
181
182impl From<String> for ApiIdent {
183 fn from(value: String) -> Self {
184 Self(value)
185 }
186}
187
188impl ApiIdent {
189 pub fn versioned_api_latest_symlink(&self) -> String {
191 format!("{self}-latest.json")
192 }
193
194 pub fn versioned_api_is_latest_symlink(&self, base_name: &str) -> bool {
197 base_name == self.versioned_api_latest_symlink()
198 }
199}