Год назад возникла идея переписать весь Java-бекенд на Rust, который я уже несколько лет разрабатываю и поддерживаю. Я нашёл все аналоги библиотек и фреймворков из мира Java в экосистеме Rust:
Spring Framework = Axum
Jackson = Serde
Hibernate = SeaORM
Bouncy Castle = Rustls
В мире Rust я не смог найти аналог только одной библиотеке — JasperReports, которая используется для генерации отчётов. По этой причине пришлось отказаться от идеи переписывать весь проект на Rust.

Так как ниша по генерации ответов на Rust пуста, я создал свой open source проект — генератор отчетов.
Решил не изобретать велосипед, поэтому многие идеи взял от JasperReports. Например, чтобы сгенерировать отчёт, нужно две вещи:
Шаблон отчёта.
Данные, которые нужно подставить в отчёт.
Я выбрал шаблон отчёта в формате YAML, а не XML, так как YAML легче читать и редактировать для человека. Кстати, именно по этой причине в JasperReports имеется WYSIWYG-редактор шаблона отчёта — ориентироваться в XML довольно тяжело.
Пример шаблона отчета:
title: - header: $P{company_name} Employee Report level: 1 page_header: - text: "Confidential information\n\n" size: 7 column_header: - name: Name width: 30 - name: Age width: 10 - name: Salary width: 20 row: - value: $F(name) - value: $F(age) - value: $F(salary) column_footer: - value: "Average:" - value: $P{average_age} - value: $P{average_salary} page_footer: - text: "Tel: +1 123 456 789" size: 7 summary: - paragraph: - text: "Company address: $P{company_address}" size: 10
Шаблон состоит из следующих частей:
title - Заголовок отчета. Этот раздел содержит название отчета и используется для ясного обозначения темы или содержания документа. Это первое, что видит пользователь, открывая документ.
page_header - Верхний колонтитул страницы. Эта секция используется для вставки общей информации, которая должна отображаться на верхней части каждой страницы отчета.
column_header - Заголовки столбцов. В этом разделе указываются наименования столбцов и их ширина, что обеспечивает структурированное и четкое представление данных в таблицах отчета.
row - Строки данных. Секция предназначена для отображения конкретных значений данных. Это позволяет последовательно и читаемо представлять информацию о каждом элементе данных в соответствующем столбце.
column_footer - Подвал столбцов. Этот раздел используется для вывода итоговой или подытоживающей информации по данным столбцов.
page_footer - Нижний колонтитул страницы. З��есь размещается информация, которая должна быть легко доступна на каждой странице отчета.
summary - Сводка отчета. Итоговая информация после таблицы отчета.
При переборе строк таблицы доступ к ячейкам можно получить через выражение $F(COLUMN_NAME). Также в отчете поддерживаются глобальные параметры, доступ к которым можно получить через выражение $P(PARAM_NAME).
Пример данных для отчета:
{ "rows": [ { "name": "John", "age": 25, "salary": 50000 }, { "name": "Jane", "age": 30, "salary": 60000 }, { "name": "Jim", "age": 35, "salary": 70000 } ], "params": { "company_name": "ABCDFG Ltd", "company_address": "1234 Elm St, Springfield, IL 62701", "average_age": 30, "average_salary": 60000 } }
Я не стал создавать структуру и требовать, чтобы данные были в неё помещены перед вызовом библиотеки. На вход ожидаю просто набор байтов, в которых будет JSON следующего формата.
Для использования библиотеки Metatron добавьте в файл Cargo.toml:
[dependencies] metatron = "0.2.1"
Пример использования генератора отчетов:
fn main() { let template_vec = std::fs::read("report-template.yaml").unwrap(); let template = std::str::from_utf8(&template_vec).unwrap(); let data_vec = std::fs::read("report-data.json").unwrap(); let data = std::str::from_utf8(&data_vec).unwrap(); let images = HashMap::new(); let doc = Report::generate(template, data, &images).unwrap(); let result = shiva::pdf::Transformer::generate(&doc).unwrap(); std::fs::write("report.pdf",result.0).unwrap(); }
Обратите внимание на строку 'let result = shiva::pdf::Transformer::generate(&doc).unwrap();'. Я использую для сериализации отчета библиотеку Shiva, которая на текущий момент поддерживает форматы: Plain text, Markdown, HTML и PDF. Другими словами, в строке 'let doc = Report::generate(template, data, &images).unwrap()' мы получаем отчет в Common Document Model (CDM), поддерживаемом библиотекой Shiva. В дальнейшем, по мере роста количества поддерживаемых форматов документов этой библиотекой, Metatron тоже сможет автоматически генерировать отчеты в новых форматах.
В итоге получается такой report.pdf

На текущий момент этот проект находится в стадии MVP (Minimum Viable Product). В ближайшем будущем планирую добавить:
Поддержку картинок
CLI
REST API сервер
Суботчеты
Название "Metatron" для библиотеки было вдохновлено несколькими ассоциативными характеристиками ангела Метатрона:
Записывающий ангел: Метатрон часто ассоциируется с канцелярией и записями. Считается, что он записывает все действия и события во Вселенной. Эта ассоциация с делопроизводством и ведением записей отражает основную функцию библиотеки генератора отчетов.
Мост между небесным и земным: Метатрон также известен как посредник между Божественным и человеческим, облегчая общение и понимание. В контексте библиотеки это может символизировать преобразование данных в понятные и доступные формы отчетов.
Исходный код проекта опубликован на GitHub. Если кто-то желает помочь с проектом, пишите на email.