1use bc_components::XID;
39use dcbor::prelude::*;
40use crate::{Envelope, Assertion, string_utils::StringUtils, FormatContext, with_format_context};
41#[cfg(feature = "known_value")]
42use crate::{KnownValue, known_values};
43
44use super::{EnvelopeSummary, envelope::EnvelopeCase};
45
46impl Envelope {
48 pub fn format_opt(&self, context: Option<&FormatContext>) -> String {
50 let context = context.cloned().unwrap_or(FormatContext::default());
51 self.format_item(&context).format(context.is_flat()).trim().to_string()
52 }
53
54 pub fn format(&self) -> String {
58 with_format_context!(|context| {
59 self.format_opt(Some(context))
60 })
61 }
62
63 pub fn format_flat(&self) -> String {
67 with_format_context!(|context: &FormatContext| {
68 let context = context.clone().set_flat(true);
69 self.format_opt(Some(&context))
70 })
71 }
72
73 pub fn diagnostic_annotated(&self) -> String {
78 with_format_context!(|context: &FormatContext| {
79 self.tagged_cbor().diagnostic_opt(true, false, false, Some(context.tags()))
80 })
81 }
82
83 pub fn diagnostic(&self) -> String {
90 self.tagged_cbor().diagnostic()
91 }
92
93 pub fn hex_opt(&self, annotate: bool, context: Option<&FormatContext>) -> String {
98 let cbor: CBOR = self.clone().into();
99 cbor.hex_opt(annotate, Some(context.unwrap_or(&FormatContext::default()).tags()))
100 }
101
102 pub fn hex(&self) -> String {
109 with_format_context!(|context| {
110 self.hex_opt(true, Some(context))
111 })
112 }
113}
114
115pub trait EnvelopeFormat {
117 fn format_item(&self, context: &FormatContext) -> EnvelopeFormatItem;
118}
119
120#[derive(Debug, Clone, Eq)]
122pub enum EnvelopeFormatItem {
123 Begin(String),
124 End(String),
125 Item(String),
126 Separator,
127 List(Vec<EnvelopeFormatItem>),
128}
129
130impl EnvelopeFormatItem {
131 fn flatten(&self) -> Vec<EnvelopeFormatItem> {
132 match self {
133 EnvelopeFormatItem::List(items) => items.iter().flat_map(|i| i.flatten()).collect(),
134 _ => vec![self.clone()],
135 }
136 }
137
138 fn nicen(items: &[EnvelopeFormatItem]) -> Vec<EnvelopeFormatItem> {
139 let mut input = items.to_vec();
140 let mut result: Vec<EnvelopeFormatItem> = vec![];
141
142 while !input.is_empty() {
143 let current = input.remove(0);
144 if input.is_empty() {
145 result.push(current);
146 break;
147 }
148 if let EnvelopeFormatItem::End(end_string) = current.clone() {
149 if let EnvelopeFormatItem::Begin(begin_string) = input[0].clone() {
150 result.push(EnvelopeFormatItem::End(format!("{} {}", end_string, begin_string)));
151 result.push(EnvelopeFormatItem::Begin("".to_string()));
152 input.remove(0);
153 } else {
154 result.push(current);
155 }
156 } else {
157 result.push(current);
158 }
159 }
160
161 result
162 }
163
164 fn indent(level: usize) -> String {
165 " ".repeat(level * 4)
166 }
167
168 fn add_space_at_end_if_needed(s: &str) -> String {
169 if s.is_empty() {
170 " ".to_string()
171 } else if s.ends_with(' ') {
172 s.to_string()
173 } else {
174 s.to_string() + " "
175 }
176 }
177
178 fn format(&self, is_flat: bool) -> String {
179 if is_flat {
180 return self.format_flat();
181 }
182 self.format_hierarchical()
183 }
184
185 fn format_flat(&self) -> String {
186 let mut line: String = "".to_string();
187 let items = self.flatten();
188 for item in items {
189 match item {
190 EnvelopeFormatItem::Begin(s) => {
191 if !line.ends_with(' ') {
192 line += " ";
193 }
194 line += &s;
195 line += " ";
196 },
197 EnvelopeFormatItem::End(s) => {
198 if !line.ends_with(' ') {
199 line += " ";
200 }
201 line += &s;
202 line += " ";
203 },
204 EnvelopeFormatItem::Item(s) => line += &s,
205 EnvelopeFormatItem::Separator => {
206 line = line.trim_end().to_string() + ", ";
207 },
208 EnvelopeFormatItem::List(items) => {
209 for item in items {
210 line += &item.format_flat();
211 }
212 }
213 }
214 }
215 line
216 }
217
218 fn format_hierarchical(&self) -> String {
219 let mut lines: Vec<String> = vec![];
220 let mut level = 0;
221 let mut current_line = "".to_string();
222 let items = Self::nicen(&self.flatten());
223 for item in items {
224 match item {
225 EnvelopeFormatItem::Begin(delimiter) => {
226 if !delimiter.is_empty() {
227 let c = if current_line.is_empty() {
228 delimiter
229 } else {
230 Self::add_space_at_end_if_needed(¤t_line) + &delimiter
231 };
232 lines.push(Self::indent(level) + &c + "\n");
233 }
234 level += 1;
235 current_line = "".to_string();
236 }
237 EnvelopeFormatItem::End(delimiter) => {
238 if !current_line.is_empty() {
239 lines.push(Self::indent(level) + ¤t_line + "\n");
240 current_line = "".to_string();
241 }
242 level -= 1;
243 lines.push(Self::indent(level) + &delimiter + "\n");
244 }
245 EnvelopeFormatItem::Item(string) => {
246 current_line += &string;
247 }
248 EnvelopeFormatItem::Separator => {
249 if !current_line.is_empty() {
250 lines.push(Self::indent(level) + ¤t_line + "\n");
251 current_line = "".to_string();
252 }
253 }
254 EnvelopeFormatItem::List(_) => {
255 lines.push("<list>".to_string());
256 }
257 }
258 }
259 if !current_line.is_empty() {
260 lines.push(current_line);
261 }
262 lines.join("")
263 }
264}
265
266impl From<&str> for EnvelopeFormatItem {
268 fn from(s: &str) -> Self {
269 Self::Item(s.to_string())
270 }
271}
272
273impl std::fmt::Display for EnvelopeFormatItem {
275 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
276 match self {
277 EnvelopeFormatItem::Begin(s) => write!(f, ".begin({})", s),
278 EnvelopeFormatItem::End(s) => write!(f, ".end({})", s),
279 EnvelopeFormatItem::Item(s) => write!(f, ".item({})", s),
280 EnvelopeFormatItem::Separator => write!(f, ".separator"),
281 EnvelopeFormatItem::List(items) => write!(f, ".list({:?})", items),
282 }
283 }
284}
285
286impl PartialEq for EnvelopeFormatItem {
288 fn eq(&self, other: &Self) -> bool {
289 match (self, other) {
290 (EnvelopeFormatItem::Begin(s1), EnvelopeFormatItem::Begin(s2)) => s1 == s2,
291 (EnvelopeFormatItem::End(s1), EnvelopeFormatItem::End(s2)) => s1 == s2,
292 (EnvelopeFormatItem::Item(s1), EnvelopeFormatItem::Item(s2)) => s1 == s2,
293 (EnvelopeFormatItem::Separator, EnvelopeFormatItem::Separator) => true,
294 (EnvelopeFormatItem::List(items1), EnvelopeFormatItem::List(items2)) => items1 == items2,
295 _ => false,
296 }
297 }
298}
299
300impl EnvelopeFormatItem {
301 fn index(&self) -> u32 {
302 match self {
303 EnvelopeFormatItem::Begin(_) => 1,
304 EnvelopeFormatItem::End(_) => 2,
305 EnvelopeFormatItem::Item(_) => 3,
306 EnvelopeFormatItem::Separator => 4,
307 EnvelopeFormatItem::List(_) => 5,
308 }
309 }
310}
311
312impl PartialOrd for EnvelopeFormatItem {
314 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
315 Some(self.cmp(other))
316 }
317}
318
319
320impl Ord for EnvelopeFormatItem {
322 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
323 let l_index = self.index();
324 let r_index = other.index();
325 match l_index.cmp(&r_index) {
326 std::cmp::Ordering::Less => return std::cmp::Ordering::Less,
327 std::cmp::Ordering::Greater => return std::cmp::Ordering::Greater,
328 _ => {}
329 }
330 match (self, other) {
331 (EnvelopeFormatItem::Begin(l), EnvelopeFormatItem::Begin(r)) => l.cmp(r),
332 (EnvelopeFormatItem::End(l), EnvelopeFormatItem::End(r)) => l.cmp(r),
333 (EnvelopeFormatItem::Item(l), EnvelopeFormatItem::Item(r)) => l.cmp(r),
334 (EnvelopeFormatItem::Separator, EnvelopeFormatItem::Separator) => std::cmp::Ordering::Equal,
335 (EnvelopeFormatItem::List(l), EnvelopeFormatItem::List(r)) => l.cmp(r),
336 _ => std::cmp::Ordering::Equal,
337 }
338 }
339}
340
341impl EnvelopeFormat for CBOR {
355 fn format_item(&self, context: &FormatContext) -> EnvelopeFormatItem {
356 match self.as_case() {
357 CBORCase::Tagged(tag, cbor) if tag == &Envelope::cbor_tags()[0] => {
358 Envelope::from_untagged_cbor(cbor.clone())
359 .map(|envelope| envelope.format_item(context))
360 .unwrap_or_else(|_| "<error>".into())
361 }
362 _ => EnvelopeFormatItem::Item(
363 self.envelope_summary(usize::MAX, context)
364 .unwrap_or_else(|_| "<error>".into())
365 ),
366 }
367 }
368}
369
370impl EnvelopeFormat for Envelope {
372 fn format_item(&self, context: &FormatContext) -> EnvelopeFormatItem {
373 match self.case() {
374 EnvelopeCase::Leaf { cbor, .. } => cbor.format_item(context),
375 EnvelopeCase::Wrapped { envelope, .. } => EnvelopeFormatItem::List(vec![
376 EnvelopeFormatItem::Begin("{".to_string()),
377 envelope.format_item(context),
378 EnvelopeFormatItem::End("}".to_string()),
379 ]),
380 EnvelopeCase::Assertion(assertion) => assertion.format_item(context),
381 #[cfg(feature = "known_value")]
382 EnvelopeCase::KnownValue { value, .. } => value.format_item(context),
383 #[cfg(feature = "encrypt")]
384 EnvelopeCase::Encrypted(_) => EnvelopeFormatItem::Item("ENCRYPTED".to_string()),
385 #[cfg(feature = "compress")]
386 EnvelopeCase::Compressed(_) => EnvelopeFormatItem::Item("COMPRESSED".to_string()),
387 EnvelopeCase::Node { subject, assertions, .. } => {
388 let mut items: Vec<EnvelopeFormatItem> = Vec::new();
389
390 let subject_item = subject.format_item(context);
391 let mut elided_count = 0;
392 #[cfg(feature = "encrypt")]
393 let mut encrypted_count = 0;
394 #[cfg(feature = "compress")]
395 let mut compressed_count = 0;
396 #[cfg(feature = "known_value")]
397 let mut type_assertion_items: Vec<Vec<EnvelopeFormatItem>> = Vec::new();
398 let mut assertion_items: Vec<Vec<EnvelopeFormatItem>> = Vec::new();
399
400 for assertion in assertions {
401 match assertion.case() {
402 EnvelopeCase::Elided(_) => {
403 elided_count += 1;
404 },
405 #[cfg(feature = "encrypt")]
406 EnvelopeCase::Encrypted(_) => {
407 encrypted_count += 1;
408 },
409 #[cfg(feature = "compress")]
410 EnvelopeCase::Compressed(_) => {
411 compressed_count += 1;
412 },
413 _ => {
414 let item = vec![assertion.format_item(context)];
415 #[cfg(feature = "known_value")]
416 {
417 let mut is_type_assertion = false;
418 if let Some(predicate) = assertion.as_predicate() {
419 if let Some(known_value) = predicate.subject().as_known_value() {
420 if *known_value == known_values::IS_A {
421 is_type_assertion = true;
422 }
423 }
424 }
425 if is_type_assertion {
426 type_assertion_items.push(item);
427 } else {
428 assertion_items.push(item);
429 }
430 }
431 #[cfg(not(feature = "known_value"))]
432 assertion_items.push(item);
433 },
434 }
435 }
436 #[cfg(feature = "known_value")]
437 type_assertion_items.sort();
438 assertion_items.sort();
439 #[cfg(feature = "known_value")]
440 assertion_items.splice(0..0, type_assertion_items);
441 #[cfg(feature = "compress")]
442 if compressed_count > 1 {
443 assertion_items.push(vec![EnvelopeFormatItem::Item(format!("COMPRESSED ({})", compressed_count))]);
444 } else if compressed_count > 0 {
445 assertion_items.push(vec![EnvelopeFormatItem::Item("COMPRESSED".to_string())]);
446 }
447 if elided_count > 1 {
448 assertion_items.push(vec![EnvelopeFormatItem::Item(format!("ELIDED ({})", elided_count))]);
449 } else if elided_count > 0 {
450 assertion_items.push(vec![EnvelopeFormatItem::Item("ELIDED".to_string())]);
451 }
452 #[cfg(feature = "encrypt")]
453 if encrypted_count > 1 {
454 assertion_items.push(vec![EnvelopeFormatItem::Item(format!("ENCRYPTED ({})", encrypted_count))]);
455 } else if encrypted_count > 0 {
456 assertion_items.push(vec![EnvelopeFormatItem::Item("ENCRYPTED".to_string())]);
457 }
458 let joined_assertions_items: Vec<Vec<EnvelopeFormatItem>> =
459 itertools::intersperse_with(assertion_items, || vec![EnvelopeFormatItem::Separator]).collect();
460
461 let needs_braces = subject.is_subject_assertion();
462
463 if needs_braces {
464 items.push(EnvelopeFormatItem::Begin("{".to_string()));
465 }
466 items.push(subject_item);
467 if needs_braces {
468 items.push(EnvelopeFormatItem::End("}".to_string()));
469 }
470 items.push(EnvelopeFormatItem::Begin("[".to_string()));
471 items.extend(joined_assertions_items.into_iter().flatten());
472 items.push(EnvelopeFormatItem::End("]".to_string()));
473 EnvelopeFormatItem::List(items)
474 },
475 EnvelopeCase::Elided(_) => EnvelopeFormatItem::Item("ELIDED".to_string()),
476 }
477 }
478}
479
480impl EnvelopeFormat for Assertion {
482 fn format_item(&self, context: &FormatContext) -> EnvelopeFormatItem {
483 EnvelopeFormatItem::List(vec![
484 self.predicate().format_item(context),
485 EnvelopeFormatItem::Item(": ".to_string()),
486 self.object().format_item(context),
487 ])
488 }
489}
490
491#[cfg(feature = "known_value")]
492impl EnvelopeFormat for KnownValue {
494 fn format_item(&self, context: &FormatContext) -> EnvelopeFormatItem {
495 EnvelopeFormatItem::Item(context
496 .known_values()
497 .assigned_name(self)
498 .map(|s| s.to_string())
499 .unwrap_or_else(|| self.name())
500 .flanked_by("'", "'")
501 )
502 }
503}
504
505impl EnvelopeFormat for XID {
507 fn format_item(&self, _context: &FormatContext) -> EnvelopeFormatItem {
508 EnvelopeFormatItem::Item(hex::encode(self.data()))
509 }
510}
511
512 impl Envelope {
513 fn description(&self, context: Option<&FormatContext>) -> String {
514 match self.case() {
515 EnvelopeCase::Node { subject, assertions, .. } => {
516 let assertions = assertions
517 .iter()
518 .map(|a| a.to_string())
519 .collect::<Vec<String>>()
520 .join(", ")
521 .flanked_by("[", "]");
522 format!(".node({}, {})", subject, assertions)
523 }
524 EnvelopeCase::Leaf { cbor, .. } => format!(".cbor({})", cbor.format_item(context.unwrap_or(&FormatContext::default()))),
525 EnvelopeCase::Wrapped { envelope, .. } => format!(".wrapped({})", envelope),
526 EnvelopeCase::Assertion(assertion) => format!(".assertion({}, {})", assertion.predicate(), assertion.object()),
527 EnvelopeCase::Elided(_) => ".elided".to_string(),
528 #[cfg(feature = "known_value")]
529 EnvelopeCase::KnownValue { value, .. } => format!(".knownValue({})", value),
530 #[cfg(feature = "encrypt")]
531 EnvelopeCase::Encrypted(_) => ".encrypted".to_string(),
532 #[cfg(feature = "compress")]
533 EnvelopeCase::Compressed(_) => ".compressed".to_string(),
534 }
535 }
536}
537
538impl std::fmt::Display for Envelope {
540 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
541 f.write_str(&self.description(None))
542 }
543}