1#![no_std]
2#![deny(missing_docs)]
3
4extern crate alloc;
55extern crate core as std;
56
57mod error;
58mod global_items;
59mod local_items;
60mod macros;
61mod main_items;
62mod privates;
63mod reserved;
64
65use alloc::{
66 format,
67 string::{String, ToString},
68 vec::Vec,
69};
70use std::fmt::Display;
71
72pub use error::*;
73pub use global_items::*;
74pub use local_items::*;
75pub use main_items::*;
76pub(crate) use privates::*;
77pub use reserved::*;
78
79#[derive(Clone, Debug, PartialEq, Eq)]
122pub enum ReportItem {
123 Input(Input),
125 Output(Output),
127 Feature(Feature),
129 Collection(Collection),
131 EndCollection(EndCollection),
133 UsagePage(UsagePage),
135 LogicalMinimum(LogicalMinimum),
137 LogicalMaximum(LogicalMaximum),
139 PhysicalMinimum(PhysicalMinimum),
141 PhysicalMaximum(PhysicalMaximum),
143 UnitExponent(UnitExponent),
145 Unit(Unit),
147 ReportSize(ReportSize),
149 ReportId(ReportId),
151 ReportCount(ReportCount),
153 Push(Push),
155 Pop(Pop),
157 Usage(Usage),
159 UsageMinimum(UsageMinimum),
161 UsageMaximum(UsageMaximum),
163 DesignatorIndex(DesignatorIndex),
165 DesignatorMinimum(DesignatorMinimum),
167 DesignatorMaximum(DesignatorMaximum),
169 StringIndex(StringIndex),
171 StringMinimum(StringMinimum),
173 StringMaximum(StringMaximum),
175 Delimiter(Delimiter),
177 Reserved(Reserved),
179}
180
181impl AsRef<[u8]> for ReportItem {
182 fn as_ref(&self) -> &[u8] {
183 match self {
184 ReportItem::Input(inner) => inner.as_ref(),
185 ReportItem::Output(inner) => inner.as_ref(),
186 ReportItem::Feature(inner) => inner.as_ref(),
187 ReportItem::Collection(inner) => inner.as_ref(),
188 ReportItem::EndCollection(inner) => inner.as_ref(),
189 ReportItem::UsagePage(inner) => inner.as_ref(),
190 ReportItem::LogicalMinimum(inner) => inner.as_ref(),
191 ReportItem::LogicalMaximum(inner) => inner.as_ref(),
192 ReportItem::PhysicalMinimum(inner) => inner.as_ref(),
193 ReportItem::PhysicalMaximum(inner) => inner.as_ref(),
194 ReportItem::UnitExponent(inner) => inner.as_ref(),
195 ReportItem::Unit(inner) => inner.as_ref(),
196 ReportItem::ReportSize(inner) => inner.as_ref(),
197 ReportItem::ReportId(inner) => inner.as_ref(),
198 ReportItem::ReportCount(inner) => inner.as_ref(),
199 ReportItem::Push(inner) => inner.as_ref(),
200 ReportItem::Pop(inner) => inner.as_ref(),
201 ReportItem::Usage(inner) => inner.as_ref(),
202 ReportItem::UsageMinimum(inner) => inner.as_ref(),
203 ReportItem::UsageMaximum(inner) => inner.as_ref(),
204 ReportItem::DesignatorIndex(inner) => inner.as_ref(),
205 ReportItem::DesignatorMinimum(inner) => inner.as_ref(),
206 ReportItem::DesignatorMaximum(inner) => inner.as_ref(),
207 ReportItem::StringIndex(inner) => inner.as_ref(),
208 ReportItem::StringMinimum(inner) => inner.as_ref(),
209 ReportItem::StringMaximum(inner) => inner.as_ref(),
210 ReportItem::Delimiter(inner) => inner.as_ref(),
211 ReportItem::Reserved(inner) => inner.as_ref(),
212 }
213 }
214}
215
216impl Display for ReportItem {
217 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
218 match self {
219 ReportItem::Input(inner) => inner.fmt(f),
220 ReportItem::Output(inner) => inner.fmt(f),
221 ReportItem::Feature(inner) => inner.fmt(f),
222 ReportItem::Collection(inner) => inner.fmt(f),
223 ReportItem::EndCollection(inner) => inner.fmt(f),
224 ReportItem::UsagePage(inner) => inner.fmt(f),
225 ReportItem::LogicalMinimum(inner) => inner.fmt(f),
226 ReportItem::LogicalMaximum(inner) => inner.fmt(f),
227 ReportItem::PhysicalMinimum(inner) => inner.fmt(f),
228 ReportItem::PhysicalMaximum(inner) => inner.fmt(f),
229 ReportItem::UnitExponent(inner) => inner.fmt(f),
230 ReportItem::Unit(inner) => inner.fmt(f),
231 ReportItem::ReportSize(inner) => inner.fmt(f),
232 ReportItem::ReportId(inner) => inner.fmt(f),
233 ReportItem::ReportCount(inner) => inner.fmt(f),
234 ReportItem::Push(inner) => inner.fmt(f),
235 ReportItem::Pop(inner) => inner.fmt(f),
236 ReportItem::Usage(inner) => inner.fmt(f),
237 ReportItem::UsageMinimum(inner) => inner.fmt(f),
238 ReportItem::UsageMaximum(inner) => inner.fmt(f),
239 ReportItem::DesignatorIndex(inner) => inner.fmt(f),
240 ReportItem::DesignatorMinimum(inner) => inner.fmt(f),
241 ReportItem::DesignatorMaximum(inner) => inner.fmt(f),
242 ReportItem::StringIndex(inner) => inner.fmt(f),
243 ReportItem::StringMinimum(inner) => inner.fmt(f),
244 ReportItem::StringMaximum(inner) => inner.fmt(f),
245 ReportItem::Delimiter(inner) => inner.fmt(f),
246 ReportItem::Reserved(inner) => inner.fmt(f),
247 }
248 }
249}
250
251impl ReportItem {
252 pub fn new(raw: &[u8]) -> Result<Self, HidError> {
268 if raw.is_empty() {
269 return Err(HidError::EmptyRawInput);
270 };
271 let expected = __data_size(raw[0]);
272 if expected + 1 != raw.len() {
273 return Err(HidError::DataSizeNotMatch {
274 expected,
275 provided: raw.len() - 1,
276 });
277 };
278 unsafe {
279 Ok(match raw[0] & 0b1111_1100 {
280 Input::PREFIX => ReportItem::Input(Input::new_unchecked(raw)),
281 Output::PREFIX => ReportItem::Output(Output::new_unchecked(raw)),
282 Feature::PREFIX => ReportItem::Feature(Feature::new_unchecked(raw)),
283 Collection::PREFIX => ReportItem::Collection(Collection::new_unchecked(raw)),
284 EndCollection::PREFIX => {
285 ReportItem::EndCollection(EndCollection::new_unchecked(raw))
286 }
287 UsagePage::PREFIX => ReportItem::UsagePage(UsagePage::new_unchecked(raw)),
288 LogicalMinimum::PREFIX => {
289 ReportItem::LogicalMinimum(LogicalMinimum::new_unchecked(raw))
290 }
291 LogicalMaximum::PREFIX => {
292 ReportItem::LogicalMaximum(LogicalMaximum::new_unchecked(raw))
293 }
294 PhysicalMinimum::PREFIX => {
295 ReportItem::PhysicalMinimum(PhysicalMinimum::new_unchecked(raw))
296 }
297 PhysicalMaximum::PREFIX => {
298 ReportItem::PhysicalMaximum(PhysicalMaximum::new_unchecked(raw))
299 }
300 UnitExponent::PREFIX => ReportItem::UnitExponent(UnitExponent::new_unchecked(raw)),
301 Unit::PREFIX => ReportItem::Unit(Unit::new_unchecked(raw)),
302 ReportSize::PREFIX => ReportItem::ReportSize(ReportSize::new_unchecked(raw)),
303 ReportId::PREFIX => ReportItem::ReportId(ReportId::new_unchecked(raw)),
304 ReportCount::PREFIX => ReportItem::ReportCount(ReportCount::new_unchecked(raw)),
305 Push::PREFIX => ReportItem::Push(Push::new_unchecked(raw)),
306 Pop::PREFIX => ReportItem::Pop(Pop::new_unchecked(raw)),
307 Usage::PREFIX => ReportItem::Usage(Usage::new_unchecked(raw)),
308 UsageMinimum::PREFIX => ReportItem::UsageMinimum(UsageMinimum::new_unchecked(raw)),
309 UsageMaximum::PREFIX => ReportItem::UsageMaximum(UsageMaximum::new_unchecked(raw)),
310 DesignatorIndex::PREFIX => {
311 ReportItem::DesignatorIndex(DesignatorIndex::new_unchecked(raw))
312 }
313 DesignatorMinimum::PREFIX => {
314 ReportItem::DesignatorMinimum(DesignatorMinimum::new_unchecked(raw))
315 }
316 DesignatorMaximum::PREFIX => {
317 ReportItem::DesignatorMaximum(DesignatorMaximum::new_unchecked(raw))
318 }
319 StringIndex::PREFIX => ReportItem::StringIndex(StringIndex::new_unchecked(raw)),
320 StringMinimum::PREFIX => {
321 ReportItem::StringMinimum(StringMinimum::new_unchecked(raw))
322 }
323 StringMaximum::PREFIX => {
324 ReportItem::StringMaximum(StringMaximum::new_unchecked(raw))
325 }
326 Delimiter::PREFIX => ReportItem::Delimiter(Delimiter::new_unchecked(raw)),
327 _ => ReportItem::Reserved(Reserved::new_unchecked(raw)),
328 })
329 }
330 }
331
332 pub fn new_strict(raw: &[u8]) -> Result<Self, crate::HidError> {
336 if raw.is_empty() {
337 return Err(crate::HidError::EmptyRawInput);
338 };
339 let expected = __data_size(raw[0]);
340 if expected + 1 != raw.len() {
341 return Err(HidError::DataSizeNotMatch {
342 expected,
343 provided: raw.len() - 1,
344 });
345 };
346 unsafe {
347 Ok(match raw[0] & 0b1111_1100 {
348 Input::PREFIX => ReportItem::Input(Input::new_unchecked(raw)),
349 Output::PREFIX => ReportItem::Output(Output::new_unchecked(raw)),
350 Feature::PREFIX => ReportItem::Feature(Feature::new_unchecked(raw)),
351 Collection::PREFIX => ReportItem::Collection(Collection::new_unchecked(raw)),
352 EndCollection::PREFIX => {
353 ReportItem::EndCollection(EndCollection::new_unchecked(raw))
354 }
355 UsagePage::PREFIX => ReportItem::UsagePage(UsagePage::new_unchecked(raw)),
356 LogicalMinimum::PREFIX => {
357 ReportItem::LogicalMinimum(LogicalMinimum::new_unchecked(raw))
358 }
359 LogicalMaximum::PREFIX => {
360 ReportItem::LogicalMaximum(LogicalMaximum::new_unchecked(raw))
361 }
362 PhysicalMinimum::PREFIX => {
363 ReportItem::PhysicalMinimum(PhysicalMinimum::new_unchecked(raw))
364 }
365 PhysicalMaximum::PREFIX => {
366 ReportItem::PhysicalMaximum(PhysicalMaximum::new_unchecked(raw))
367 }
368 UnitExponent::PREFIX => ReportItem::UnitExponent(UnitExponent::new_unchecked(raw)),
369 Unit::PREFIX => ReportItem::Unit(Unit::new_unchecked(raw)),
370 ReportSize::PREFIX => ReportItem::ReportSize(ReportSize::new_unchecked(raw)),
371 ReportId::PREFIX => ReportItem::ReportId(ReportId::new_unchecked(raw)),
372 ReportCount::PREFIX => ReportItem::ReportCount(ReportCount::new_unchecked(raw)),
373 Push::PREFIX => ReportItem::Push(Push::new_unchecked(raw)),
374 Pop::PREFIX => ReportItem::Pop(Pop::new_unchecked(raw)),
375 Usage::PREFIX => ReportItem::Usage(Usage::new_unchecked(raw)),
376 UsageMinimum::PREFIX => ReportItem::UsageMinimum(UsageMinimum::new_unchecked(raw)),
377 UsageMaximum::PREFIX => ReportItem::UsageMaximum(UsageMaximum::new_unchecked(raw)),
378 DesignatorIndex::PREFIX => {
379 ReportItem::DesignatorIndex(DesignatorIndex::new_unchecked(raw))
380 }
381 DesignatorMinimum::PREFIX => {
382 ReportItem::DesignatorMinimum(DesignatorMinimum::new_unchecked(raw))
383 }
384 DesignatorMaximum::PREFIX => {
385 ReportItem::DesignatorMaximum(DesignatorMaximum::new_unchecked(raw))
386 }
387 StringIndex::PREFIX => ReportItem::StringIndex(StringIndex::new_unchecked(raw)),
388 StringMinimum::PREFIX => {
389 ReportItem::StringMinimum(StringMinimum::new_unchecked(raw))
390 }
391 StringMaximum::PREFIX => {
392 ReportItem::StringMaximum(StringMaximum::new_unchecked(raw))
393 }
394 Delimiter::PREFIX => ReportItem::Delimiter(Delimiter::new_unchecked(raw)),
395 _ => return Err(HidError::ReservedItem(Reserved::new_unchecked(raw))),
396 })
397 }
398 }
399
400 pub unsafe fn new_unchecked(raw: &[u8]) -> Self {
410 match raw[0] & 0b1111_1100 {
411 Input::PREFIX => ReportItem::Input(Input::new_unchecked(raw)),
412 Output::PREFIX => ReportItem::Output(Output::new_unchecked(raw)),
413 Feature::PREFIX => ReportItem::Feature(Feature::new_unchecked(raw)),
414 Collection::PREFIX => ReportItem::Collection(Collection::new_unchecked(raw)),
415 EndCollection::PREFIX => ReportItem::EndCollection(EndCollection::new_unchecked(raw)),
416 UsagePage::PREFIX => ReportItem::UsagePage(UsagePage::new_unchecked(raw)),
417 LogicalMinimum::PREFIX => {
418 ReportItem::LogicalMinimum(LogicalMinimum::new_unchecked(raw))
419 }
420 LogicalMaximum::PREFIX => {
421 ReportItem::LogicalMaximum(LogicalMaximum::new_unchecked(raw))
422 }
423 PhysicalMinimum::PREFIX => {
424 ReportItem::PhysicalMinimum(PhysicalMinimum::new_unchecked(raw))
425 }
426 PhysicalMaximum::PREFIX => {
427 ReportItem::PhysicalMaximum(PhysicalMaximum::new_unchecked(raw))
428 }
429 UnitExponent::PREFIX => ReportItem::UnitExponent(UnitExponent::new_unchecked(raw)),
430 Unit::PREFIX => ReportItem::Unit(Unit::new_unchecked(raw)),
431 ReportSize::PREFIX => ReportItem::ReportSize(ReportSize::new_unchecked(raw)),
432 ReportId::PREFIX => ReportItem::ReportId(ReportId::new_unchecked(raw)),
433 ReportCount::PREFIX => ReportItem::ReportCount(ReportCount::new_unchecked(raw)),
434 Push::PREFIX => ReportItem::Push(Push::new_unchecked(raw)),
435 Pop::PREFIX => ReportItem::Pop(Pop::new_unchecked(raw)),
436 Usage::PREFIX => ReportItem::Usage(Usage::new_unchecked(raw)),
437 UsageMinimum::PREFIX => ReportItem::UsageMinimum(UsageMinimum::new_unchecked(raw)),
438 UsageMaximum::PREFIX => ReportItem::UsageMaximum(UsageMaximum::new_unchecked(raw)),
439 DesignatorIndex::PREFIX => {
440 ReportItem::DesignatorIndex(DesignatorIndex::new_unchecked(raw))
441 }
442 DesignatorMinimum::PREFIX => {
443 ReportItem::DesignatorMinimum(DesignatorMinimum::new_unchecked(raw))
444 }
445 DesignatorMaximum::PREFIX => {
446 ReportItem::DesignatorMaximum(DesignatorMaximum::new_unchecked(raw))
447 }
448 StringIndex::PREFIX => ReportItem::StringIndex(StringIndex::new_unchecked(raw)),
449 StringMinimum::PREFIX => ReportItem::StringMinimum(StringMinimum::new_unchecked(raw)),
450 StringMaximum::PREFIX => ReportItem::StringMaximum(StringMaximum::new_unchecked(raw)),
451 Delimiter::PREFIX => ReportItem::Delimiter(Delimiter::new_unchecked(raw)),
452 _ => ReportItem::Reserved(Reserved::new_unchecked(raw)),
453 }
454 }
455
456 pub unsafe fn new_strict_unchecked(raw: &[u8]) -> Result<Self, HidError> {
465 Ok(match raw[0] & 0b1111_1100 {
466 Input::PREFIX => ReportItem::Input(Input::new_unchecked(raw)),
467 Output::PREFIX => ReportItem::Output(Output::new_unchecked(raw)),
468 Feature::PREFIX => ReportItem::Feature(Feature::new_unchecked(raw)),
469 Collection::PREFIX => ReportItem::Collection(Collection::new_unchecked(raw)),
470 EndCollection::PREFIX => ReportItem::EndCollection(EndCollection::new_unchecked(raw)),
471 UsagePage::PREFIX => ReportItem::UsagePage(UsagePage::new_unchecked(raw)),
472 LogicalMinimum::PREFIX => {
473 ReportItem::LogicalMinimum(LogicalMinimum::new_unchecked(raw))
474 }
475 LogicalMaximum::PREFIX => {
476 ReportItem::LogicalMaximum(LogicalMaximum::new_unchecked(raw))
477 }
478 PhysicalMinimum::PREFIX => {
479 ReportItem::PhysicalMinimum(PhysicalMinimum::new_unchecked(raw))
480 }
481 PhysicalMaximum::PREFIX => {
482 ReportItem::PhysicalMaximum(PhysicalMaximum::new_unchecked(raw))
483 }
484 UnitExponent::PREFIX => ReportItem::UnitExponent(UnitExponent::new_unchecked(raw)),
485 Unit::PREFIX => ReportItem::Unit(Unit::new_unchecked(raw)),
486 ReportSize::PREFIX => ReportItem::ReportSize(ReportSize::new_unchecked(raw)),
487 ReportId::PREFIX => ReportItem::ReportId(ReportId::new_unchecked(raw)),
488 ReportCount::PREFIX => ReportItem::ReportCount(ReportCount::new_unchecked(raw)),
489 Push::PREFIX => ReportItem::Push(Push::new_unchecked(raw)),
490 Pop::PREFIX => ReportItem::Pop(Pop::new_unchecked(raw)),
491 Usage::PREFIX => ReportItem::Usage(Usage::new_unchecked(raw)),
492 UsageMinimum::PREFIX => ReportItem::UsageMinimum(UsageMinimum::new_unchecked(raw)),
493 UsageMaximum::PREFIX => ReportItem::UsageMaximum(UsageMaximum::new_unchecked(raw)),
494 DesignatorIndex::PREFIX => {
495 ReportItem::DesignatorIndex(DesignatorIndex::new_unchecked(raw))
496 }
497 DesignatorMinimum::PREFIX => {
498 ReportItem::DesignatorMinimum(DesignatorMinimum::new_unchecked(raw))
499 }
500 DesignatorMaximum::PREFIX => {
501 ReportItem::DesignatorMaximum(DesignatorMaximum::new_unchecked(raw))
502 }
503 StringIndex::PREFIX => ReportItem::StringIndex(StringIndex::new_unchecked(raw)),
504 StringMinimum::PREFIX => ReportItem::StringMinimum(StringMinimum::new_unchecked(raw)),
505 StringMaximum::PREFIX => ReportItem::StringMaximum(StringMaximum::new_unchecked(raw)),
506 Delimiter::PREFIX => ReportItem::Delimiter(Delimiter::new_unchecked(raw)),
507 _ => return Err(HidError::ReservedItem(Reserved::new_unchecked(raw))),
508 })
509 }
510
511 pub fn prefix(&self) -> u8 {
513 self.as_ref()[0]
514 }
515
516 pub fn data(&self) -> &[u8] {
518 &self.as_ref()[1..]
519 }
520}
521
522struct Iter<ByteStreamIter: Iterator<Item = u8>> {
523 byte_stream_iter: ByteStreamIter,
524 usage_page: Option<UsagePage>,
525}
526
527struct StrictIter<ByteStreamIter: Iterator<Item = u8>> {
528 byte_stream_iter: ByteStreamIter,
529 usage_page: Option<UsagePage>,
530}
531
532impl<ByteStreamIter: Iterator<Item = u8>> Iterator for Iter<ByteStreamIter> {
533 type Item = ReportItem;
534 fn next(&mut self) -> Option<Self::Item> {
535 let prefix = self.byte_stream_iter.next()?;
536 let size = __data_size(prefix);
537 let mut storage = [0u8; 5];
538 storage[0] = prefix;
539 for i in 0..size {
540 storage[i + 1] = self.byte_stream_iter.next()?;
541 }
542 let mut item = unsafe { ReportItem::new_unchecked(&storage) };
543 if let ReportItem::UsagePage(usage_page) = &item {
544 self.usage_page = Some(usage_page.clone());
545 }
546 if let Some(usage_page) = &self.usage_page {
547 match &mut item {
548 ReportItem::Usage(usage) => usage.set_usage_page(usage_page.clone()),
549 ReportItem::UsageMinimum(usage_minimum) => {
550 usage_minimum.set_usage_page(usage_page.clone())
551 }
552 ReportItem::UsageMaximum(usage_maximum) => {
553 usage_maximum.set_usage_page(usage_page.clone())
554 }
555 _ => (),
556 }
557 }
558 Some(item)
559 }
560}
561
562impl<ByteStreamIter: Iterator<Item = u8>> Iterator for StrictIter<ByteStreamIter> {
563 type Item = Result<ReportItem, HidError>;
564 fn next(&mut self) -> Option<Self::Item> {
565 let prefix = self.byte_stream_iter.next()?;
566 let size = __data_size(prefix);
567 let mut storage = [0u8; 5];
568 storage[0] = prefix;
569 for i in 0..size {
570 storage[i + 1] = self.byte_stream_iter.next()?;
571 }
572 let mut item = unsafe { ReportItem::new_strict_unchecked(&storage) };
573 if let Ok(ReportItem::UsagePage(usage_page)) = &item {
574 self.usage_page = Some(usage_page.clone());
575 }
576 if let Some(usage_page) = &self.usage_page {
577 match &mut item {
578 Ok(ReportItem::Usage(usage)) => usage.set_usage_page(usage_page.clone()),
579 Ok(ReportItem::UsageMinimum(usage_minimum)) => {
580 usage_minimum.set_usage_page(usage_page.clone())
581 }
582 Ok(ReportItem::UsageMaximum(usage_maximum)) => {
583 usage_maximum.set_usage_page(usage_page.clone())
584 }
585 _ => (),
586 }
587 }
588 Some(item)
589 }
590}
591
592pub fn parse<ByteStream: IntoIterator<Item = u8>>(
626 byte_stream: ByteStream,
627) -> impl Iterator<Item = ReportItem> {
628 Iter {
629 byte_stream_iter: byte_stream.into_iter(),
630 usage_page: None,
631 }
632}
633
634pub fn parse_strict<ByteStream: IntoIterator<Item = u8>>(
639 byte_stream: ByteStream,
640) -> impl Iterator<Item = Result<ReportItem, HidError>> {
641 StrictIter {
642 byte_stream_iter: byte_stream.into_iter(),
643 usage_page: None,
644 }
645}
646
647pub fn dump<'a, ItemStream: IntoIterator<Item = &'a ReportItem>>(
649 item_stream: ItemStream,
650) -> Vec<u8> {
651 let mut v = Vec::new();
652 for item in item_stream {
653 v.extend_from_slice(item.as_ref());
654 }
655 v
656}
657
658pub fn pretty_print<'a, ItemStream: IntoIterator<Item = &'a ReportItem>>(
690 item_stream: ItemStream,
691) -> String {
692 let mut max_len = 0;
693 let mut tmp = Vec::new();
694 let mut tab: usize = 0;
695 for item in item_stream {
696 match item {
697 ReportItem::Collection(_) | ReportItem::Push(_) => tab += 1,
698 ReportItem::EndCollection(_) | ReportItem::Pop(_) => tab = tab.saturating_sub(1),
699 _ => (),
700 }
701 max_len = std::cmp::max(max_len, item.as_ref().len());
702 tmp.push((
703 item.as_ref()
704 .iter()
705 .map(|byte| format!("{:#04X}", byte))
706 .collect::<Vec<_>>()
707 .join(", "),
708 item.to_string(),
709 tab * 2 + 1,
710 ));
711 }
712 let width_of_raw = max_len * 6;
713 tmp.into_iter()
714 .map(|(raw, comment, tab)| format!("{:<width_of_raw$}//{:<tab$}{}", raw, ' ', comment))
715 .collect::<Vec<_>>()
716 .join("\n")
717}