У 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 {

}

И вроде бы очевидно, чего пытался добиться автор библиотеки: безопасного доступа к объектам без утечек памяти. И провел он большую, качественную работу. Только пользоваться этим, увы, неудобно.