У godot-rust есть два архитектурных компромисса, которые часто меня дико накаляют.
1. Вездесущие Gd. Смарт-поинтер на объекты в ядре движка лишают прямого контроля за тем, как и где живут данные. Вся библиотека — всего лишь биндинги для движка, написанного на C++. Соотвественно, все объекты движка (сцены и refcounted объекты) и взаимодействия (сигналы и методы) "гуляют" через FFI-границу. А мы, как разработчики, платим удобством за безопасный мост между этими слоями. 2. Насильное и неорганичное натягивание ООП-парадигмы на Rust. Godot глубоко объектно-ориентированный: классы, наследование, виртуальные методы. В Rust мимикрия под ООП выглядит откровенно хуево. Вместо композиции и трейтов я вынужден мыслить иерархиями объектов с мнимой "базовой" логикой. Теряется сама суть Rust и выглядит код, поверьте мне, неприглядно.
use godot::prelude::*;
#[derive(GodotClass)] #[class(base = Node)] pub struct ContextMenuApi { base: Base, }
// "Наследование" и виртуальные методы #[godot_api] impl INode for ContextMenuApi { fn init(base: Base) -> Self { Self { base, } } }
// Реализация чисто растовых функций #[godot_api] impl ContextMenuApi { // Сигналы и функции, доступные из GDScript }
// Реализация чисто растовых функций impl ContextMenuApi {
}
И вроде бы очевидно, чего пытался добиться автор библиотеки: безопасного доступа к объектам без утечек памяти. И провел он большую, качественную работу. Только пользоваться этим, увы, неудобно.