1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// SPDX-FileCopyrightText: 2025 RAprogramm <andrey.rozanov.vl@gmail.com>
//
// SPDX-License-Identifier: MIT
//! Utilities for building custom error derive infrastructure.
//!
//! This module exposes lower-level building blocks that will eventually power
//! a native replacement for the `thiserror` derive. The initial goal is to
//! parse and validate display templates (`#[error("...")]`) in a reusable
//! and well-tested manner so that future procedural macros can focus on
//! generating code.
//!
//! The API is intentionally low level. It makes no assumptions about how the
//! parsed data is going to be used and instead provides precise spans and
//! formatting metadata that higher-level code can rely on.
//!
//! ## Formatter traits
//!
//! `TemplateFormatter` enumerates the formatting modes supported by
//! `#[error("...")]` placeholders. It mirrors the formatter detection logic in
//! `thiserror` v2 so migrating existing derives is a drop-in change.
//! `TemplateFormatter::is_alternate()` surfaces the `#` flag, and
//! [`TemplateFormatterKind`](crate::error::template::TemplateFormatterKind)
//! describes the underlying `core::fmt` trait with helpers like
//! `specifier()`/`supports_alternate()` for programmatic inspection.
//!
//! ```rust
//! use core::ptr;
//!
//! use masterror::Error;
//!
//! #[derive(Debug, Error)]
//! #[error(
//! "debug={payload:?}, hex={id:#x}, ptr={ptr:p}, bin={mask:#b}, \
//! oct={mask:o}, lower={ratio:e}, upper={ratio:E}"
//! )]
//! struct FormatterShowcase {
//! id: u32,
//! payload: String,
//! ptr: *const u8,
//! mask: u8,
//! ratio: f32
//! }
//!
//! let err = FormatterShowcase {
//! id: 0x2a,
//! payload: "hello".into(),
//! ptr: ptr::null(),
//! mask: 0b1010_0001,
//! ratio: 0.15625
//! };
//!
//! let rendered = err.to_string();
//! assert!(rendered.contains("debug=\"hello\""));
//! assert!(rendered.contains("hex=0x2a"));
//! assert!(rendered.contains("ptr=0x0"));
//! assert!(rendered.contains("bin=0b10100001"));
//! assert!(rendered.contains("oct=241"));
//! assert!(rendered.contains("lower=1.5625e-1"));
//! assert!(rendered.contains("upper=1.5625E-1"));
//! ```
//!
//! Programmatic consumers can inspect placeholders and their requested
//! formatters via [`ErrorTemplate`](crate::error::template::ErrorTemplate):
//!
//! ```rust
//! use masterror::error::template::{ErrorTemplate, TemplateFormatter, TemplateFormatterKind};
//!
//! let template = ErrorTemplate::parse("{code:#x} → {payload:?}").expect("parse");
//! let mut placeholders = template.placeholders();
//!
//! let code = placeholders.next().expect("code placeholder");
//! let code_formatter = code.formatter();
//! assert!(matches!(
//! code_formatter,
//! TemplateFormatter::LowerHex {
//! alternate: true
//! }
//! ));
//! let code_kind = code_formatter.kind();
//! assert_eq!(code_kind, TemplateFormatterKind::LowerHex);
//! assert!(code_formatter.is_alternate());
//! assert_eq!(code_kind.specifier(), Some('x'));
//! assert!(code_kind.supports_alternate());
//! let lowered = TemplateFormatter::from_kind(code_kind, false);
//! assert!(matches!(
//! lowered,
//! TemplateFormatter::LowerHex {
//! alternate: false
//! }
//! ));
//!
//! let payload = placeholders.next().expect("payload placeholder");
//! let payload_formatter = payload.formatter();
//! assert_eq!(
//! payload_formatter,
//! &TemplateFormatter::Debug {
//! alternate: false
//! }
//! );
//! let payload_kind = payload_formatter.kind();
//! assert_eq!(payload_kind, TemplateFormatterKind::Debug);
//! assert_eq!(payload_kind.specifier(), Some('?'));
//! assert!(payload_kind.supports_alternate());
//! let pretty_debug = TemplateFormatter::from_kind(payload_kind, true);
//! assert!(matches!(
//! pretty_debug,
//! TemplateFormatter::Debug {
//! alternate: true
//! }
//! ));
//! assert!(pretty_debug.is_alternate());
//! ```
/// Parser and formatter helpers for `#[error("...")]` templates.