Comments 12
В Rust нет стандартного выражения для целочисленных перечислений. Для определения типа перечисления используем псевдоним на существующий базовый тип с помощью ключевого слова type. Перечислители объявляем константами.
Вообще‐то есть. У пакета num-traits также есть FromPrimitive, упрощающий каст в такой enum (derive для него поддерживается в отдельном пакете).
Ну нельзя же делать вот так:
#[derive(Debug, Clone, Copy)]
pub struct EventDescription {
pointer: *mut ffi::FMOD_STUDIO_EVENTDESCRIPTION,
}
Если вы используете FMOD_STUDIO_EVENTDESCRIPTION, и одновременно выгружаете систему через FMOD_Studio_System_Release — будет ошибка. Нужно либо удерживать сильную ссылку на System, чтобы предотвратить такую выгрузку:
#[derive(Debug, Clone)]
pub struct EventDescription {
owner: Arc<System>,
pointer: *mut ffi::FMOD_STUDIO_EVENTDESCRIPTION,
}
Либо использовать возможности Rust чтобы не дать этого сделать на этапе компиляции:
#[derive(Debug, Clone, Copy)]
pub struct EventDescription<`a> {
pointer: *mut ffi::FMOD_STUDIO_EVENTDESCRIPTION,
owner: PhantomData<&`a System>,
}
А ещё лучше, раз уж вы всё равно генерируете код — использовать сразу оба подхода.
И да, надеюсь что у вас System реализует Drop.
Спасибо, дельное замечание. Сначала тоже думал переложить на Rust высвобождение ресурсов, реализовать в Drop вызов FMOD_Studio_System_Release
и прочее. Но FMOD в любом случае подразумевает ответственность со стороны разработчика за порядок работы с API. Например:
Если пойти в обратную сторону, любой работе с FMOD объектами должен предшествовать
FMOD_Studio_System_Initialize
, а это подразумевает строгость типов вроде отдельныхSystem
иInitializedSystem
Банки выгружать через Drop нельзя, потому что есть сценарии, где это должно происходить только вручную
В итоге хорошо бы сделать более безопасный и строгий интерфейс, но это уже скорее следующий уровень абстракции, который предполагает изменение FMOD API в Rust стиле. Это, на мой взгляд, выходит за рамки обёртки, которая просто скрывает работу с указателями и небезопасным FFI.
Но FMOD в любом случае подразумевает ответственность со стороны разработчика за порядок работы с API.
Вот именно этот порядок и надо переложить на Rust, благо механизмы есть. Иначе вы, по-хорошему, не можете называть ваше API словом "safe".
Если пойти в обратную сторону, любой работе с FMOD объектами должен предшествовать FMOD_Studio_System_Initialize, а это подразумевает строгость типов вроде отдельных System и InitializedSystem
Отдельные System и InitializedSystem не нужны, потому что вы можете скомбинировать эти вызовы.
Банки выгружать через Drop нельзя, потому что есть сценарии, где это должно происходить только вручную
Только вручную потому что ..? Если потому что требуется соблюдение инвариантов — то за ними должен следить компилятор, а не программист. Если потому что программисту требуется определённое время жизни — ну так пусть держит ссылку.
В общем, не должно быть таких сценариев.
Идейно я с вами согласен. Но в данном случае приходится учитывать несовершенство реального мира. Эта Rust обёртка небезопасна настолько, насколько это заложено в оригинальном FMOD API, в контексте наших примеров:
Комбинировать
FMOD_Studio_System_Create
иFMOD_Studio_System_Initialize
нельзя потому что между ними могут быть другие вызовыFMOD работает как "отдельный процесс", загруженные банки могут использоваться в процессе независимо от количества ссылок на них в Rust приложении
Чтобы это исправить и сделать "как должно быть" нужно отдельное решение, которое бы опиралось на принципы и механизмы Rust, а не фактический FMOD C API. А это уже сложнее чем генератор обёртки, дороже, и вопрос целесообразности.
Приходится идти на компромисс, я об этом.
Но это неправильно. API обёртки должно "обернуть", в том числе, и гарантии.
Комбинировать FMOD_Studio_System_Create и FMOD_Studio_System_Initialize нельзя потому что между ними могут быть другие вызовы
Вы же сами написали, что при любой работе с FMOD надо сначала инициализировать систему. Так откуда возьмутся другие вызовы и что они там будут делать?
FMOD работает как "отдельный процесс", загруженные банки могут использоваться в процессе независимо от количества ссылок на них в Rust приложении
И чем это мешает сделать нормальное API?
А это уже сложнее чем генератор обёртки, дороже, и вопрос целесообразности.
Не виду ничего особенно сложного. Просто частично вывести из генерируемой обёртки структуры системы и банков данных.
Rust — хороший выбор для разработки игр.
Можно ли небольшое пояснение, почему он так хорош для разработки игр?
Любой аспект, о котором я могу задуматься, говорит о том, что раст хуже C++ для разработки игр.
Генерируем Rust обёртку для FMOD