Цели дизайна
Явные коды и домены
thiserror форматирует сообщение, но не даёт стабильных кодов. Введи:
ErrorCode(NonZeroU32) и ErrorDomain(&'static str).
Инвариант: код стабилен, сообщение и поля — нет.
Диапазоны кодов per-crate/перенейминг через макрос домена.
Прозрачный рантайм: ноль лишних аллокаций
Display строится без format! при конструировании.
Сообщение — &'static str + форматирование аргументов на выводе.
Опциональный Backtrace по фиче, захват один раз при создании.
Минимальный proc-macro
Зависимости только proc_macro2, syn, quote. Никаких reflection-трюков, никаких «скрытых» From на всё подряд.
Атрибуты валидируются жёстко, ошибки — диагностически понятные.
Интероп и миграция
From<anyhow::Error>/Into<anyhow::Error> по фиче.
Маппинг thiserror-стиля: #[source], #[transparent], форматные строки.
Утилиты: chain() итератор по причинам, report() для человекочитаемого трейсинга.
Контекст и структурные данные без глобального стейта
Лёгкий Context как иммутабельный key-value snapshot (SmallVec<[(&'static str, Cow<'static, str>); N]>), без мутабельного глобала.
По фиче serde — сериализация структурных данных.
MSRV/скорость компиляции
MSRV = актуальный LTS/твоя корпоративная, без «танцев» в макросе.
Меньше генерируемого кода: без дублирующих From/Display там, где можно обойтись общими трейтом-адаптерами.
---
Реализация: план работ
core
Трейты MasterError, ErrorCategory, Context, итератор chain(), Report для красивого вывода.
Фичи: backtrace, serde, anyhow, miette.
derive
Парсер атрибутов (только syn/quote).
Проверки: единственный #[source]; запрет transparent вместе с кастомным #[error("…")]; обязательность #[code(..)].
Генерация Display с match, без промежуточных String.
интеграции
impl From<T> for E только по явному #[from].
Into<anyhow::Error> по фиче: сохраняем code/domain в anyhow::Context через newtype-адаптер и downcast_ref.
UX-инструменты
err! и bail! макросы, которые не плодят типы, а создают твой enum? Нет. Оставь это anyhow. Дай макрос ensure!(cond, MyError::X { … }) как удобство, но без магии.
#[deny(masterror::missing_code)] внутренняя диагностическая либа на базе rustc lints через proc_macro_diagnostic для ранней обратной связи.
Документация и примеры
Cookbook: «миграция с thiserror за 15 минут».
Пример с Axum: маппинг на HTTP-статусы по category() и логирование кода/домена.
Выход на прод: чек-лист