TL; DR: Добавьте #[repr(C)]
и вам должно быть хорошо.
Здесь есть две отдельные проблемы: действителен ли трансмут в смысле возврата действительногоданные в возвращаемом типе и нарушает ли все это какие-либо инварианты более высокого уровня, которые могут быть присоединены к вовлеченным типам.(В терминологии моего сообщения в блоге вы должны убедиться, что инварианты действительности и безопасности соблюдаются.)
Для инварианта действительности вы находитесь на неизведанной территории.Компилятор может решить расположить Map<T, M>
очень иначе, чем Map<T, ()>
, то есть поле data
может иметь другое смещение и может быть ложное заполнение.Это кажется маловероятным, но пока мы здесь гарантируем очень мало.Обсуждение того, что мы можем и хотим гарантировать, что происходит прямо сейчас .Мы намеренно хотим не давать слишком много гарантий о repr(Rust)
, чтобы не рисовать себя в углу.
Что вы можете сделать, это добавить repr(C)
в вашу структуру, тогда я вполне уверен, что вы можете рассчитывать наЗСТ ничего не меняет (но я попросил уточнить просто чтобы быть уверенным).Для repr(C)
мы предоставляем больше гарантий о том, как устроена структура, что фактически является ее целью.Если вы хотите разыгрывать трюки со структурной разметкой, вам, вероятно, следует добавить этот атрибут.
Для инварианта безопасности более высокого уровня вы должны быть осторожны, чтобы не создать сломанный Map
и позволить этой «утечке» за пределыграницы вашего API (в окружающий безопасный код), то есть вы не должны возвращать экземпляр Map
, который нарушает любые инварианты, которые вы могли бы на него надеть.Более того, PhantomData
оказывает некоторое влияние на дисперсию и проверку на падение, о которых вам следует знать.Поскольку трансмутируемые типы являются настолько тривиальными (типы маркеров не требуют отбрасывания, т. Е. Все они и их переходные поля не реализуют Drop
), я не думаю, что вам следует ожидать каких-либо проблем с этой стороны.
Для ясности, repr(Rust)
(по умолчанию) может также подойти, если мы решим, что это то, что мы хотим гарантировать - и полное игнорирование типов size-0-align-1 (например, PhantomData
) выглядит так:довольно разумная гарантия для меня.Лично я все же посоветовал бы использовать repr(C)
, если это не связано с расходами, которые вы не готовы платить (например, из-за того, что вы теряете компиляторы автоматически уменьшая размер за счет переупорядочения и не можете копировать его вручную).