Формат маршала
Формат Marshal используется для сериализации объектов Ruby. Этот формат может хранить произвольные объекты с помощью трёх механизмов пользовательских расширений.
Для получения документации по использованию Marshal для сериализации и десериализации объектов, см. модуль Marshal.
В данном документе сериализованный набор объектов называется потоком. Реализация Ruby может загрузить набор объектов из строки, объекта IO или объекта, реализующего метод getc.
Формат потока
Первые два байта потока содержат основную и дополнительную версии, каждая в виде одного байта, кодирующего цифру. Реализация Ruby использует версию 4.8 (хранится как “x04x08”) и поддерживается ruby 1.8.0 и более новыми версиями.
Разные основные версии формата Marshal несовместимы и не могут быть поняты другими основными версиями. Более поздние дополнительные версии формата могут быть поняты более новыми дополнительными версиями. Формат 4.7 может быть загружен реализацией 4.8, но формат 4.8 не может быть загружен реализацией 4.7.
После байтов версии следует поток, описывающий сериализованный объект. Поток содержит вложенные объекты (так же, как и объект Ruby), но объекты в потоке не обязательно имеют прямое отображение в модели объекта Ruby.
Каждый объект в потоке описывается байтом, указывающим его тип, за которым следует один или несколько байтов, описывающих объект. Когда ниже упоминается «объект», это означает любой из типов ниже, определяющих объект Ruby.
true, false, nil
Эти объекты имеют длину в один байт. «T» представляет true, «F» представляет false, а «0» представляет nil.
Fixnum и long
«i» представляет целое 32-битовое со знаком, используя упакованный формат. За типом следуют от одного до пяти байтов. Загруженное значение всегда будет Fixnum. На 32-битных платформах (где точность Fixnum меньше 32 бит), загрузка больших значений вызовет переполнение в CRuby.
Тип fixnum используется для представления как объектов Ruby Fixnum, так и размеров сериализованных массивов, хешей, переменных экземпляра и других типов. В следующих разделах «long» будет означать формат, описанный ниже, который поддерживает полную 32-битную точность.
Первый байт имеет следующие специальные значения:
- “x00”
-
Значение целого числа равно 0. Следующие байты отсутствуют.
- “x01”
-
Общий размер целого числа равен двум байтам. Следующий байт — положительное целое число в диапазоне от 0 до 255. Только значения от 123 до 255 должны быть представлены таким образом для экономии байтов.
- “xff”
-
Общий размер целого числа равен двум байтам. Следующий байт — отрицательное целое число в диапазоне от -1 до -256.
- “x02”
-
Общий размер целого числа равен трём байтам. Следующие два байта — положительное целое число в формате little-endian.
- “xfe”
-
Общий размер целого числа равен трём байтам. Следующие два байта — отрицательное целое число в формате little-endian.
- “x03”
-
Общий размер целого числа равен четырём байтам. Следующие три байта — положительное целое число в формате little-endian.
- “xfd”
-
Общий размер целого числа равен четырём байтам. Следующие три байта — отрицательное целое число в формате little-endian.
- “x04”
-
Общий размер целого числа равен пяти байтам. Следующие четыре байта — положительное целое число в формате little-endian. Для совместимости с 32-битным ruby, только Fixnums меньше 1073741824 должны быть представлены таким образом. Для размеров объектов потока может использоваться полная точность.
- “xfc”
-
Общий размер целого числа равен пяти байтам. Следующие четыре байта — отрицательное целое число в формате little-endian. Для совместимости с 32-битным ruby, только Fixnums больше -10737341824 должны быть представлены таким образом. Для размеров объектов потока может использоваться полная точность.
В противном случае первый байт — это значение восьмиразрядного расширенного знака с смещением. Если значение положительное, значение определяется вычитанием 5 из значения. Если значение отрицательное, значение определяется добавлением 5 к значению.
Существует несколько представлений для многих значений. CRuby всегда выводит наименьшее возможное представление.
Символы и последовательность байтов
«:” представляет реальный символ. Реальный символ содержит данные, необходимые для определения символа для остальной части потока, так как последующие вхождения в поток будут вместо этого ссылками (символьная ссылка) на этот. Ссылка — это нулево-индексированное 32-битовое значение (так что первое вхождение :hello равно 0).
За байтом типа следует последовательность байтов, которая состоит из целого числа, указывающего количество байтов в последовательности, за которым следует столько байтов данных. Последовательности байтов не имеют кодировки.
Например, следующий поток содержит символ :hello:
"\x04\x08:\x0ahello"
«;” представляет ссылку на символ, которая ссылается на ранее определённый символ. За байтом типа следует целое число, содержащее индекс в таблице поиска для связанного (ссылочного) символа.
Например, следующий поток содержит [:hello, :hello]:
"\x04\b[\a:\nhello;\x00"
Когда ниже упоминается «символ», это может быть либо реальный символ, либо ссылка на символ.
Ссылки на объекты
Отдельно, но аналогично ссылкам на символы, поток содержит только одну копию каждого объекта (как определяется object_id) для всех объектов, кроме true, false, nil, Fixnums и Symbols (которые хранятся отдельно, как описано выше). Будет храниться одноиндексированное 32-битовое значение и повторно использоваться при повторной встрече объекта. (Первый объект имеет индекс 1).
«@» представляет ссылку на объект. За байтом типа следует целое число, указывающее индекс объекта.
Например, следующий поток содержит массив из того же "hello" объекта дважды:
"\004\b[\a\"\nhello@\006"
Переменные экземпляра
«I» указывает, что за следующим объектом следуют переменные экземпляра. За байтом типа следует объект. За объектом следует длина, указывающая количество переменных экземпляра для объекта. За длиной следует набор пар имя-значение. Имена — символы, а значения — объекты. Символы должны быть именами переменных экземпляра (:@name).
Объект («o» тип, описанный ниже) использует тот же формат для своих переменных экземпляра, что и описанный здесь.
Для строки и регулярного выражения (описанных ниже) используется специальная переменная экземпляра :E для обозначения кодировки.
Расширенный
«e» указывает, что следующий объект расширен модулем. За байтом типа следует объект. За объектом следует символ, содержащий имя модуля, которым расширен объект.
Массив
“[” представляет массив. За байтом типа следует целое число, указывающее количество объектов в массиве. За длиной следуют указанное количество объектов.
Большое целое число
«l» представляет большое целое число, которое состоит из трёх частей:
- знак
-
Один байт, содержащий «+» для положительного значения или «-» для отрицательного значения.
- длина
-
Целое число, указывающее количество байтов данных большого целого числа, которые следуют за ним, делённое на два. Умножьте длину на два, чтобы определить количество байтов данных, которые следуют за ней.
- данные
-
Байты данных большого целого числа, представляющие число.
Следующий код Ruby восстановит значение большого целого числа из массива байтов:
result = 0 bytes.each_with_index do |byte, exp| result += (byte * 2 ** (exp * 8)) end
Класс и Модуль
«c» представляет объект класса, «m» представляет объект модуля, а «M» представляет либо класс, либо модуль (это старый стиль для совместимости). Содержимое класса или модуля не включено, этот тип только ссылка. За байтом типа следует последовательность байтов, которая используется для поиска существующего класса или модуля соответственно.
Переменные экземпляра не допускаются для класса или модуля.
Если класс или модуль не существует, должно быть выброшено исключение.
Для типов «c» и «m» загруженный объект должен быть соответственно классом или модулем.
«d» представляет объект Data. (Объекты Data — это обернутые указатели из расширений Ruby.) За байтом типа следует символ, указывающий класс для объекта Data, и объект, содержащий состояние объекта Data.
Для сохранения объекта Data Ruby вызывает _dump_data. Для загрузки объекта Data Ruby вызывает _load_data со состоянием объекта в вновь выделенном экземпляре.
Число с плавающей точкой
«f» представляет объект числа с плавающей точкой. За байтом типа следует последовательность байтов, содержащая значение числа с плавающей точкой. Следующие значения являются специальными:
- “inf”
-
Положительная бесконечность
- “-inf”
-
Отрицательная бесконечность
- “nan”
-
Не число
В противном случае последовательность байтов содержит C double (загружаемое с помощью strtod(3)). Более ранние дополнительные версии Marshal также хранили дополнительные биты мантиссы для обеспечения переносимости между платформами, но 4.8 не включает их. См.
- ruby-talk:69518
-
для некоторых объяснений.
Хеш и хеш со значением по умолчанию
«{» представляет объект хеш, а «}» представляет хеш с установленным значением по умолчанию (Hash.new
0). За байтом типа следует целое число, указывающее количество пар ключ-значение в хеше, размер. За размером следуют удвоенные значения указанного количества объектов.
Для хеша со значением по умолчанию значение по умолчанию следует за всеми парами.
Модуль и старый модуль
Объект
«o» представляет собой объект, у которого нет другого специального формата (например, пользовательского или встроенного формата). За байтом типа следует символ, содержащий имя класса объекта. За именем класса следует целое число, указывающее количество имён и значений переменных экземпляра для объекта. Удвоенные значения указанного количества пар объектов следуют за размером.
Ключи в парах должны быть символами, содержащими имена переменных экземпляра.
Регулярное выражение
«/» представляет регулярное выражение. За байтом типа следует последовательность байтов, содержащая исходный код регулярного выражения. За типом следует байт, содержащий параметры регулярного выражения (регистронезависимый и т. д.) в виде 8-битового значения со знаком.
Регулярные выражения могут иметь присоединённую кодировку через переменные экземпляра (см. выше). Если кодировка не присоединёна, спецсимволы регулярных выражений, отсутствующие в ruby 1.8, должны быть удалены: g-m, o-q, u, y, E, F, H-L, N-V, X, Y.
Строка
'“' представляет строку. После байта типа следует последовательность байтов, содержащая содержимое строки. При выводе из ruby 1.9 должна быть включена переменная кодировки (:E см. выше), если кодировка не двоичная.
Структура
“S” представляет структуру. После байта типа следует символ, содержащий имя структуры. После имени следует целое число, указывающее количество членов структуры. После количества членов следуют удвоенные количество объектов. Каждый член — это пара, содержащая символ члена и объект, представляющий значение этого члена.
Если имя структуры не соответствует подклассу структуры в работающей версии ruby, должно быть выброшено исключение.
Если есть несоответствие между структурой в текущей версии ruby и количеством членов в сериализованной структуре, должно быть выброшено исключение.
Класс Пользователя
“C” представляет подкласс String, Regexp, Array или Hash. После байта типа следует символ, содержащий имя подкласса. После имени — обернутый объект.
Определённый пользователем
“u” представляет объект с пользовательским форматом сериализации, использующим метод _dump и метод класса _load. После байта типа следует символ, содержащий имя класса. После имени класса следует последовательность байтов, содержащая пользовательское представление объекта.
Метод класса _load вызывается для класса со строкой, созданной из последовательности байтов.
Пользовательский Маршаллинг
“U” представляет объект с пользовательским форматом сериализации, использующим методы marshal_dump и marshal_load экземпляра. После байта типа следует символ, содержащий имя класса. После имени класса следует объект, содержащий данные.
При загрузке должен быть выделен новый экземпляр, и marshal_load должен быть вызван для экземпляра с данными.
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.