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