bc_envelope_pattern/
format.rs1#![allow(dead_code)]
2
3use bc_envelope::{
4 base::envelope::EnvelopeCase, format::EnvelopeSummary, prelude::*,
5};
6
7use crate::Path;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum PathElementFormat {
12 Summary(Option<usize>),
14 EnvelopeUR,
15 DigestUR,
16}
17
18impl Default for PathElementFormat {
19 fn default() -> Self { PathElementFormat::Summary(None) }
20}
21
22#[derive(Debug, Clone)]
24pub struct FormatPathsOpts {
25 indent: bool,
28
29 element_format: PathElementFormat,
32
33 last_element_only: bool,
37}
38
39impl Default for FormatPathsOpts {
40 fn default() -> Self {
45 Self {
46 indent: true,
47 element_format: PathElementFormat::default(),
48 last_element_only: false,
49 }
50 }
51}
52
53impl FormatPathsOpts {
54 pub fn new() -> Self { Self::default() }
56
57 pub fn indent(mut self, indent: bool) -> Self {
60 self.indent = indent;
61 self
62 }
63
64 pub fn element_format(mut self, format: PathElementFormat) -> Self {
67 self.element_format = format;
68 self
69 }
70
71 pub fn last_element_only(mut self, last_element_only: bool) -> Self {
75 self.last_element_only = last_element_only;
76 self
77 }
78}
79
80impl AsRef<FormatPathsOpts> for FormatPathsOpts {
81 fn as_ref(&self) -> &FormatPathsOpts { self }
82}
83
84pub fn envelope_summary(env: &Envelope) -> String {
85 let id = env.short_id(DigestDisplayFormat::Short);
86 let summary = match env.case() {
87 EnvelopeCase::Node { .. } => {
88 format!("NODE {}", env.format_flat())
89 }
90 EnvelopeCase::Leaf { cbor, .. } => {
91 format!(
92 "LEAF {}",
93 cbor.envelope_summary(usize::MAX, &FormatContextOpt::default())
94 .unwrap_or_else(|_| "ERROR".to_string())
95 )
96 }
97 EnvelopeCase::Wrapped { .. } => {
98 format!("WRAPPED {}", env.format_flat())
99 }
100 EnvelopeCase::Assertion(_) => {
101 format!("ASSERTION {}", env.format_flat())
102 }
103 EnvelopeCase::Elided(_) => "ELIDED".to_string(),
104 EnvelopeCase::KnownValue { value, .. } => {
105 let content = with_format_context!(|ctx: &FormatContext| {
106 let known_value = KnownValuesStore::known_value_for_raw_value(
107 value.value(),
108 Some(ctx.known_values()),
109 );
110 format!("'{}'", known_value)
111 });
112 format!("KNOWN_VALUE {}", content)
113 }
114 EnvelopeCase::Encrypted(_) => "ENCRYPTED".to_string(),
115 EnvelopeCase::Compressed(_) => "COMPRESSED".to_string(),
116 };
117 format!("{} {}", id, summary)
118}
119
120fn truncate_with_ellipsis(s: &str, max_length: Option<usize>) -> String {
123 match max_length {
124 Some(max_len) if s.len() > max_len => {
125 if max_len > 1 {
126 format!("{}…", &s[0..(max_len - 1)])
127 } else {
128 "…".to_string()
129 }
130 }
131 _ => s.to_string(),
132 }
133}
134
135pub fn format_path_opt(
138 path: &Path,
139 opts: impl AsRef<FormatPathsOpts>,
140) -> String {
141 let opts = opts.as_ref();
142
143 if opts.last_element_only {
144 if let Some(element) = path.iter().last() {
146 match opts.element_format {
147 PathElementFormat::Summary(max_length) => {
148 let summary = envelope_summary(element);
149 truncate_with_ellipsis(&summary, max_length)
150 }
151 PathElementFormat::EnvelopeUR => element.ur_string(),
152 PathElementFormat::DigestUR => element.digest().ur_string(),
153 }
154 } else {
155 String::new()
156 }
157 } else {
158 match opts.element_format {
159 PathElementFormat::Summary(max_length) => {
160 let mut lines = Vec::new();
162 for (index, element) in path.iter().enumerate() {
163 let indent = if opts.indent {
164 " ".repeat(index * 4)
165 } else {
166 String::new()
167 };
168
169 let summary = envelope_summary(element);
170 let content = truncate_with_ellipsis(&summary, max_length);
171
172 lines.push(format!("{}{}", indent, content));
173 }
174 lines.join("\n")
175 }
176 PathElementFormat::EnvelopeUR => {
177 path.iter()
179 .map(|element| element.ur_string())
180 .collect::<Vec<_>>()
181 .join(" ")
182 }
183 PathElementFormat::DigestUR => {
184 path.iter()
186 .map(|element| element.digest().ur_string())
187 .collect::<Vec<_>>()
188 .join(" ")
189 }
190 }
191 }
192}
193
194pub fn format_path(path: &Path) -> String {
197 format_path_opt(path, FormatPathsOpts::default())
198}
199
200pub fn format_paths_opt(
202 paths: &[Path],
203 opts: impl AsRef<FormatPathsOpts>,
204) -> String {
205 let opts = opts.as_ref();
206 match opts.element_format {
207 PathElementFormat::EnvelopeUR | PathElementFormat::DigestUR => {
208 paths
210 .iter()
211 .map(|path| format_path_opt(path, opts))
212 .collect::<Vec<_>>()
213 .join(" ")
214 }
215 PathElementFormat::Summary(_) => {
216 paths
218 .iter()
219 .map(|path| format_path_opt(path, opts))
220 .collect::<Vec<_>>()
221 .join("\n")
222 }
223 }
224}
225
226pub fn format_paths(paths: &[Path]) -> String {
228 format_paths_opt(paths, FormatPathsOpts::default())
229}