Переопределяющий поплавок
На данный момент (версия 1.2.4 из msgpack-ruby
) это невозможно в точности, как вы пытались: функция msgpack_packer_write_value
сначала проверяет все жестко закодированные типы данных и обрабатывает их с его реализацией по умолчанию. Расширения обрабатываются только в том случае, если текущий объект не соответствует ни одному из этих типов.
Другими словами: вы не можете переопределить форматы пакетов по умолчанию с помощью MessagePack::DefaultFactory#register_type
, вызов будет просто невозможен.
Использование расширений
Кроме того, механизм расширения - это совсем не то, на что вы смотрите. Используя это, пакет сообщений будет выдавать маркерный байт «это расширение», за которым следует идентификатор расширения (значение «0» в вашем примере), за которым следует то, что уже закодировано как float32 - в качестве альтернативы вам потребуется обработать двоичное кодирование. / расшифровывать себя.
Создание собственного класса Float
В принципе, вы можете создать свой собственный класс FloatX
или что-то еще, но это очень плохой ход:
Float
не имеет new
метода, который вы могли бы monkeypatch, и я не знаю, как сказать ruby создать экземпляр FloatX
, когда вы пишете 10.3
в своем коде. Таким образом, вам придется создавать объекты вручную во всем коде, что может серьезно повлиять на производительность.
- В любом случае, в конечном итоге вы получите механизм выдвижения, который будет невозможен, как показано выше.
Переопределение поведения msgpack_packer_write_value
Вам необходимо переопределить реализацию msgpack_packer_write_value
packer.c
. К сожалению, вы не можете сделать это в мире ruby, поскольку для него не определен эквивалентный метод ruby. Таким образом, обычная мартышечная рубиновка не может быть использована.
Кроме того, метод вызывается из множества других методов внутри реализации packer.c
, например, из соответствующих методов, отвечающих за запись массивов или хэшей. Те, конечно, также не будут вызывать метод с одним и тем же именем, так как они полностью живут в своем двоичном мире.
Наконец, хотя использование фабричного механизма, по-видимому, подразумевает, что вы можете каким-то образом создавать различные реализации упаковщиков, я не вижу никаких доказательств того, что это действительно так - читая C-код Gem, похоже, не предусмотрено что-нибудь в этом роде. Кажется, что фабрика работает с рубиновым <-> C взаимодействием Gem.
Что сейчас
Если бы я был на вашем месте, я бы клонировал этот Камень и изменил бы msgpack_packer_write_value
в packer.c
, чтобы он вел себя так, как вы хотите. Проверьте case T_FLOAT
и продолжайте. Код кажется довольно простым - вскоре он переходит к следующему методу в packer.h
:
static inline void msgpack_packer_write_float_value(msgpack_packer_t* pk, VALUE v)
{
msgpack_packer_write_double(pk, rb_num2dbl(v));
}
... что, конечно, настоящий виновник здесь.
Подходя к тому, что с другого направления (write_float32
вы уже нашли), сопоставимый код:
msgpack_packer_write_float(pk, (float)rb_num2dbl(numeric));
Итак, если вы замените эту строку в msgpack_packer_write_float_value
соответствующим образом, все будет готово. Должно быть выполнимо, даже если вы не очень любите C.
После этого вы даете своему Gem индивидуальный тег выпуска, собираете его самостоятельно и указываете его в Gemfile
или, тем не менее, управляете своими драгоценными камнями.