1use std::borrow::Cow;
4use std::fmt;
5use std::rc::Rc;
6use std::sync::mpsc;
7
8use thiserror::Error;
9
10use crate::extensions::simple::MissingReference;
11use crate::extensions::{InsertError, SimpleExtensions};
12
13pub const NONSPECIFIC: Option<&'static str> = None;
14
15#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
16pub enum Visibility {
17 Never,
19 Required,
21 Always,
23}
24
25#[derive(Debug, Clone)]
27pub struct OutputOptions {
28 pub show_extension_uris: bool,
30 pub show_simple_extensions: bool,
33 pub show_simple_extension_anchors: Visibility,
38 pub show_emit: bool,
40
41 pub read_types: bool,
43 pub literal_types: Visibility,
46 pub fn_types: bool,
48 pub nullability: bool,
50 pub indent: String,
52 pub show_literal_binaries: bool,
55}
56
57impl Default for OutputOptions {
58 fn default() -> Self {
59 Self {
60 show_extension_uris: false,
61 show_simple_extensions: false,
62 show_simple_extension_anchors: Visibility::Required,
63 literal_types: Visibility::Required,
64 show_emit: false,
65 read_types: false,
66 fn_types: false,
67 nullability: false,
68 indent: " ".to_string(),
69 show_literal_binaries: false,
70 }
71 }
72}
73
74impl OutputOptions {
75 pub fn verbose() -> Self {
78 Self {
79 show_extension_uris: true,
80 show_simple_extensions: true,
81 show_simple_extension_anchors: Visibility::Always,
82 literal_types: Visibility::Always,
83 show_emit: false,
85 read_types: true,
86 fn_types: true,
87 nullability: true,
88 indent: " ".to_string(),
89 show_literal_binaries: true,
90 }
91 }
92}
93pub trait ErrorAccumulator: Clone {
94 fn push(&self, e: FormatError);
95}
96
97#[derive(Debug, Clone)]
98pub struct ErrorQueue {
99 sender: mpsc::Sender<FormatError>,
100 receiver: Rc<mpsc::Receiver<FormatError>>,
101}
102
103impl Default for ErrorQueue {
104 fn default() -> Self {
105 let (sender, receiver) = mpsc::channel();
106 Self {
107 sender,
108 receiver: Rc::new(receiver),
109 }
110 }
111}
112
113impl From<ErrorQueue> for Vec<FormatError> {
114 fn from(v: ErrorQueue) -> Vec<FormatError> {
115 v.receiver.try_iter().collect()
116 }
117}
118
119impl ErrorAccumulator for ErrorQueue {
120 fn push(&self, e: FormatError) {
121 self.sender.send(e).unwrap();
122 }
123}
124
125impl fmt::Display for ErrorQueue {
126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127 let mut first = true;
128 for e in self.receiver.try_iter() {
129 if first {
130 first = false;
131 } else {
132 writeln!(f)?;
133 }
134 write!(f, "{e}")?;
135 }
136 Ok(())
137 }
138}
139
140impl ErrorQueue {
141 pub fn errs(self) -> Result<(), ErrorList> {
142 let errors: Vec<FormatError> = self.receiver.try_iter().collect();
143 if errors.is_empty() {
144 Ok(())
145 } else {
146 Err(ErrorList(errors))
147 }
148 }
149}
150
151pub struct ErrorList(pub Vec<FormatError>);
153
154impl ErrorList {
155 pub fn first(&self) -> &FormatError {
156 self.0
157 .first()
158 .expect("Expected at least one error in ErrorList")
159 }
160
161 pub fn is_empty(&self) -> bool {
162 self.0.is_empty()
163 }
164}
165
166impl fmt::Display for ErrorList {
167 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168 for (i, e) in self.0.iter().enumerate() {
169 if i > 0 {
170 writeln!(f)?;
171 }
172 write!(f, "{e}")?;
173 }
174 Ok(())
175 }
176}
177
178impl fmt::Debug for ErrorList {
179 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180 for (i, e) in self.0.iter().enumerate() {
181 if i == 0 {
182 writeln!(f, "Errors:")?;
183 }
184 writeln!(f, "! {e:?}")?;
185 }
186 Ok(())
187 }
188}
189
190impl<'e> IntoIterator for &'e ErrorQueue {
191 type Item = FormatError;
192 type IntoIter = std::sync::mpsc::TryIter<'e, FormatError>;
193
194 fn into_iter(self) -> Self::IntoIter {
195 self.receiver.try_iter()
196 }
197}
198
199pub trait IndentTracker {
200 #[allow(dead_code)]
202 fn indent<W: fmt::Write>(&self, w: &mut W) -> fmt::Result;
203 fn push(self) -> Self;
204}
205
206#[derive(Debug, Copy, Clone)]
207pub struct IndentStack<'a> {
208 count: u32,
209 indent: &'a str,
210}
211
212impl<'a> fmt::Display for IndentStack<'a> {
213 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214 for _ in 0..self.count {
215 f.write_str(self.indent)?;
216 }
217 Ok(())
218 }
219}
220
221#[derive(Debug, Copy, Clone)]
222pub struct ScopedContext<'a, Err: ErrorAccumulator> {
223 errors: &'a Err,
224 options: &'a OutputOptions,
225 extensions: &'a SimpleExtensions,
226 indent: IndentStack<'a>,
227}
228
229impl<'a> IndentStack<'a> {
230 pub fn new(indent: &'a str) -> Self {
231 Self { count: 0, indent }
232 }
233}
234
235impl<'a> IndentTracker for IndentStack<'a> {
236 fn indent<W: fmt::Write>(&self, w: &mut W) -> fmt::Result {
237 for _ in 0..self.count {
238 w.write_str(self.indent)?;
239 }
240 Ok(())
241 }
242
243 fn push(mut self) -> Self {
244 self.count += 1;
245 self
246 }
247}
248
249impl<'a, Err: ErrorAccumulator> ScopedContext<'a, Err> {
250 pub fn new(
251 options: &'a OutputOptions,
252 errors: &'a Err,
253 extensions: &'a SimpleExtensions,
254 ) -> Self {
255 Self {
256 options,
257 errors,
258 extensions,
259 indent: IndentStack::new(options.indent.as_str()),
260 }
261 }
262}
263
264#[derive(Error, Debug, Clone)]
266pub enum FormatError {
267 #[error("Error adding extension: {0}")]
270 Insert(#[from] InsertError),
271 #[error("Error finding extension: {0}")]
273 Lookup(#[from] MissingReference),
274 #[error("Error formatting output: {0}")]
276 Format(#[from] PlanError),
277}
278
279impl FormatError {
280 pub fn message(&self) -> &'static str {
281 match self {
282 FormatError::Lookup(MissingReference::MissingUri(_)) => "uri",
283 FormatError::Lookup(MissingReference::MissingAnchor(k, _)) => k.name(),
284 FormatError::Lookup(MissingReference::MissingName(k, _)) => k.name(),
285 FormatError::Lookup(MissingReference::Mismatched(k, _, _)) => k.name(),
286 FormatError::Lookup(MissingReference::DuplicateName(k, _)) => k.name(),
287 FormatError::Format(m) => m.message,
288 FormatError::Insert(InsertError::MissingMappingType) => "extension",
289 FormatError::Insert(InsertError::DuplicateUriAnchor { .. }) => "uri",
290 FormatError::Insert(InsertError::DuplicateAnchor { .. }) => "extension",
291 FormatError::Insert(InsertError::MissingUri { .. }) => "uri",
292 FormatError::Insert(InsertError::DuplicateAndMissingUri { .. }) => "uri",
293 }
294 }
295}
296
297#[derive(Debug, Clone)]
298pub struct PlanError {
299 pub message: &'static str,
301 pub lookup: Option<Cow<'static, str>>,
303 pub description: Cow<'static, str>,
305 pub error_type: FormatErrorType,
307}
308
309impl PlanError {
310 pub fn invalid(
311 message: &'static str,
312 specific: Option<impl Into<Cow<'static, str>>>,
313 description: impl Into<Cow<'static, str>>,
314 ) -> Self {
315 Self {
316 message,
317 lookup: specific.map(|s| s.into()),
318 description: description.into(),
319 error_type: FormatErrorType::InvalidValue,
320 }
321 }
322
323 pub fn unimplemented(
324 message: &'static str,
325 specific: Option<impl Into<Cow<'static, str>>>,
326 description: impl Into<Cow<'static, str>>,
327 ) -> Self {
328 Self {
329 message,
330 lookup: specific.map(|s| s.into()),
331 description: description.into(),
332 error_type: FormatErrorType::Unimplemented,
333 }
334 }
335
336 pub fn internal(
337 message: &'static str,
338 specific: Option<impl Into<Cow<'static, str>>>,
339 description: impl Into<Cow<'static, str>>,
340 ) -> Self {
341 Self {
342 message,
343 lookup: specific.map(|s| s.into()),
344 description: description.into(),
345 error_type: FormatErrorType::Internal,
346 }
347 }
348}
349
350#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord)]
351pub enum FormatErrorType {
352 InvalidValue,
353 Unimplemented,
354 Internal,
355}
356
357impl fmt::Display for FormatErrorType {
358 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
359 match self {
360 FormatErrorType::InvalidValue => write!(f, "InvalidValue"),
361 FormatErrorType::Unimplemented => write!(f, "Unimplemented"),
362 FormatErrorType::Internal => write!(f, "Internal"),
363 }
364 }
365}
366
367impl std::error::Error for PlanError {}
368
369impl fmt::Display for PlanError {
370 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
371 write!(
372 f,
373 "{} Error writing {}: {}",
374 self.error_type, self.message, self.description
375 )
376 }
377}
378
379#[derive(Debug, Copy, Clone)]
380pub struct ErrorToken(
382 pub &'static str,
384);
385
386impl fmt::Display for ErrorToken {
387 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
388 write!(f, "!{{{}}}", self.0)
389 }
390}
391
392#[derive(Debug, Copy, Clone)]
393pub struct MaybeToken<V: fmt::Display>(pub Result<V, ErrorToken>);
394
395impl<V: fmt::Display> fmt::Display for MaybeToken<V> {
396 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
397 match &self.0 {
398 Ok(t) => t.fmt(f),
399 Err(e) => e.fmt(f),
400 }
401 }
402}
403
404pub trait Textify {
409 fn textify<S: Scope, W: fmt::Write>(&self, ctx: &S, w: &mut W) -> fmt::Result;
410
411 fn name() -> &'static str;
414}
415
416pub trait Scope: Sized {
427 type Errors: ErrorAccumulator;
429 type Indent: IndentTracker;
430
431 fn indent(&self) -> impl fmt::Display;
433 fn push_indent(&self) -> Self;
435
436 fn options(&self) -> &OutputOptions;
438 fn extensions(&self) -> &SimpleExtensions;
439 fn errors(&self) -> &Self::Errors;
440
441 fn push_error(&self, e: FormatError) {
442 self.errors().push(e);
443 }
444
445 fn failure<E: Into<FormatError>>(&self, e: E) -> ErrorToken {
449 let e = e.into();
450 let token = ErrorToken(e.message());
451 self.push_error(e);
452 token
453 }
454
455 fn expect<'a, T: Textify>(&'a self, t: Option<&'a T>) -> MaybeToken<impl fmt::Display> {
456 match t {
457 Some(t) => MaybeToken(Ok(self.display(t))),
458 None => {
459 let err = PlanError::invalid(
460 T::name(),
461 NONSPECIFIC,
463 "Required field expected, None found",
464 );
465 let err_token = self.failure(err);
466 MaybeToken(Err(err_token))
467 }
468 }
469 }
470
471 fn expect_ok<'a, T: Textify, E: Into<FormatError>>(
472 &'a self,
473 result: Result<&'a T, E>,
474 ) -> MaybeToken<impl fmt::Display + 'a> {
475 MaybeToken(match result {
476 Ok(t) => Ok(self.display(t)),
477 Err(e) => Err(self.failure(e)),
478 })
479 }
480
481 fn display<'a, T: Textify>(&'a self, value: &'a T) -> Displayable<'a, Self, T> {
482 Displayable { scope: self, value }
483 }
484
485 fn separated<'a, T: Textify, I: IntoIterator<Item = &'a T> + Clone>(
495 &'a self,
496 items: I,
497 separator: &'static str,
498 ) -> Separated<'a, Self, T, I> {
499 Separated {
500 scope: self,
501 items,
502 separator,
503 }
504 }
505
506 fn option<'a, T: Textify>(&'a self, value: Option<&'a T>) -> OptionalDisplayable<'a, Self, T> {
507 OptionalDisplayable { scope: self, value }
508 }
509
510 fn optional<'a, T: Textify>(
511 &'a self,
512 value: &'a T,
513 option: bool,
514 ) -> OptionalDisplayable<'a, Self, T> {
515 let value = if option { Some(value) } else { None };
516 OptionalDisplayable { scope: self, value }
517 }
518}
519
520#[derive(Clone)]
521pub struct Separated<'a, S: Scope, T: Textify + 'a, I: IntoIterator<Item = &'a T> + Clone> {
522 scope: &'a S,
523 items: I,
524 separator: &'static str,
525}
526
527impl<'a, S: Scope, T: Textify, I: IntoIterator<Item = &'a T> + Clone> fmt::Display
528 for Separated<'a, S, T, I>
529{
530 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
531 for (i, item) in self.items.clone().into_iter().enumerate() {
532 if i > 0 {
533 f.write_str(self.separator)?;
534 }
535 item.textify(self.scope, f)?;
536 }
537 Ok(())
538 }
539}
540
541impl<'a, S: Scope, T: Textify, I: IntoIterator<Item = &'a T> + Clone + fmt::Debug> fmt::Debug
542 for Separated<'a, S, T, I>
543{
544 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
545 write!(
546 f,
547 "Separated{{items: {:?}, separator: {:?}}}",
548 self.items, self.separator
549 )
550 }
551}
552
553#[derive(Copy, Clone)]
554pub struct Displayable<'a, S: Scope, T: Textify> {
555 scope: &'a S,
556 value: &'a T,
557}
558
559impl<'a, S: Scope, T: Textify + fmt::Debug> fmt::Debug for Displayable<'a, S, T> {
560 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
561 write!(f, "Displayable({:?})", self.value)
562 }
563}
564
565impl<'a, S: Scope, T: Textify> Displayable<'a, S, T> {
566 pub fn new(scope: &'a S, value: &'a T) -> Self {
567 Self { scope, value }
568 }
569
570 pub fn optional(self, option: bool) -> OptionalDisplayable<'a, S, T> {
572 let value = if option { Some(self.value) } else { None };
573 OptionalDisplayable {
574 scope: self.scope,
575 value,
576 }
577 }
578}
579
580impl<'a, S: Scope, T: Textify> fmt::Display for Displayable<'a, S, T> {
581 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
582 self.value.textify(self.scope, f)
583 }
584}
585
586#[derive(Copy, Clone)]
587pub struct OptionalDisplayable<'a, S: Scope, T: Textify> {
588 scope: &'a S,
589 value: Option<&'a T>,
590}
591
592impl<'a, S: Scope, T: Textify> fmt::Display for OptionalDisplayable<'a, S, T> {
593 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
594 match &self.value {
595 Some(t) => t.textify(self.scope, f),
596 None => Ok(()),
597 }
598 }
599}
600
601impl<'a, S: Scope, T: Textify + fmt::Debug> fmt::Debug for OptionalDisplayable<'a, S, T> {
602 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
603 write!(f, "OptionalDisplayable({:?})", self.value)
604 }
605}
606
607impl<'a, Err: ErrorAccumulator> Scope for ScopedContext<'a, Err> {
608 type Errors = Err;
609 type Indent = IndentStack<'a>;
610
611 fn indent(&self) -> impl fmt::Display {
612 self.indent
613 }
614
615 fn push_indent(&self) -> Self {
616 Self {
617 indent: self.indent.push(),
618 ..*self
619 }
620 }
621
622 fn options(&self) -> &OutputOptions {
623 self.options
624 }
625
626 fn errors(&self) -> &Self::Errors {
627 self.errors
628 }
629
630 fn extensions(&self) -> &SimpleExtensions {
631 self.extensions
632 }
633}