Marshal Format

Das Marshal-Format wird zum Serialisieren von Ruby-Objekten verwendet. Das Format kann beliebige Objekte über drei benutzerdefinierte Erweiterungsmechanismen speichern.

Zur Dokumentation der Verwendung von Marshal zum Serialisieren und Deserialisieren von Objekten siehe das Modul Marshal.

Dieses Dokument bezeichnet eine serialisierte Menge von Objekten als Stream. Die Ruby-Implementierung kann eine Menge von Objekten aus einem String, einem IO oder einem Objekt, das eine getc-Methode implementiert, laden.

Stream-Format

Die ersten beiden Bytes des Streams enthalten die Haupt- und Nebenversion, jeweils als einzelnes Byte, das eine Ziffer kodiert. Die in Ruby implementierte Version ist 4.8 (gespeichert als „x04x08“) und wird von Ruby 1.8.0 und neueren Versionen unterstützt.

Unterschiedliche Hauptversionen des Marshal-Formats sind nicht kompatibel und können von anderen Hauptversionen nicht verstanden werden. Kleinere Nebenversionen des Formats können von neueren Nebenversionen verstanden werden. Format 4.7 kann von einer 4.8-Implementierung geladen werden, Format 4.8 kann jedoch nicht von einer 4.7-Implementierung geladen werden.

Auf die Versionsbytes folgt ein Stream, der das serialisierte Objekt beschreibt. Der Stream enthält verschachtelte Objekte (genau wie ein Ruby-Objekt), aber Objekte im Stream haben nicht unbedingt eine direkte Entsprechung zum Ruby-Objektmodell.

Jedes Objekt im Stream wird durch ein Byte beschrieben, das seinen Typ angibt, gefolgt von einem oder mehreren Bytes, die das Objekt beschreiben. Wenn im Folgenden von „Objekt“ die Rede ist, bedeutet dies jeden der unten aufgeführten Typen, die ein Ruby-Objekt definieren.

true, false, nil

Diese Objekte sind jeweils ein Byte lang. „T“ steht für true, „F“ für false und „0“ für nil.

Fixnum und long

„i“ steht für einen vorzeichenbehafteten 32-Bit-Wert in einem gepackten Format. Ein bis fünf Bytes folgen dem Typ. Der geladene Wert wird immer ein Fixnum sein. Auf 32-Bit-Plattformen (bei denen die Präzision eines Fixnum weniger als 32 Bits beträgt) führt das Laden großer Werte zu einem Überlauf bei CRuby.

Der Fixnum-Typ wird verwendet, um sowohl Ruby Fixnum-Objekte als auch die Größen von marshalierten Arrays, Hashes, Instanzvariablen und anderen Typen darzustellen. In den folgenden Abschnitten bedeutet „long“ das unten beschriebene Format, das die volle 32-Bit-Präzision unterstützt.

Das erste Byte hat die folgenden Sonderwerte

“x00”

Der Wert der Ganzzahl ist 0. Keine Bytes folgen.

“x01”

Die Gesamtgröße der Ganzzahl beträgt zwei Bytes. Das folgende Byte ist eine positive Ganzzahl im Bereich von 0 bis 255. Nur Werte zwischen 123 und 255 sollten auf diese Weise dargestellt werden, um Bytes zu sparen.

“xff”

Die Gesamtgröße der Ganzzahl beträgt zwei Bytes. Das folgende Byte ist eine negative Ganzzahl im Bereich von -1 bis -256.

“x02”

Die Gesamtgröße der Ganzzahl beträgt drei Bytes. Die folgenden beiden Bytes sind eine positive Little-Endian-Ganzzahl.

“xfe”

Die Gesamtgröße der Ganzzahl beträgt drei Bytes. Die folgenden beiden Bytes sind eine negative Little-Endian-Ganzzahl.

“x03”

Die Gesamtgröße der Ganzzahl beträgt vier Bytes. Die folgenden drei Bytes sind eine positive Little-Endian-Ganzzahl.

“xfd”

Die Gesamtgröße der Ganzzahl beträgt vier Bytes. Die folgenden drei Bytes sind eine negative Little-Endian-Ganzzahl.

“x04”

Die Gesamtgröße der Ganzzahl beträgt fünf Bytes. Die folgenden vier Bytes sind eine positive Little-Endian-Ganzzahl. Aus Kompatibilitätsgründen mit 32-Bit-Ruby sollten nur Fixnums kleiner als 1073741824 auf diese Weise dargestellt werden. Für Größen von Stream-Objekten kann die volle Präzision verwendet werden.

“xfc”

Die Gesamtgröße der Ganzzahl beträgt fünf Bytes. Die folgenden vier Bytes sind eine negative Little-Endian-Ganzzahl. Aus Kompatibilitätsgründen mit 32-Bit-Ruby sollten nur Fixnums größer als -10737341824 auf diese Weise dargestellt werden. Für Größen von Stream-Objekten kann die volle Präzision verwendet werden.

Andernfalls ist das erste Byte ein vorzeichenerweitertes acht-Bit-Wert mit einem Offset. Wenn der Wert positiv ist, wird der Wert durch Subtraktion von 5 vom Wert bestimmt. Wenn der Wert negativ ist, wird der Wert durch Addition von 5 zum Wert bestimmt.

Es gibt mehrere Darstellungen für viele Werte. CRuby gibt immer die kürzeste mögliche Darstellung aus.

Symbole und Byte-Sequenz

„:“ steht für ein echtes Symbol. Ein echtes Symbol enthält die Daten, die zum Definieren des Symbols für den Rest des Streams erforderlich sind, da zukünftige Vorkommen im Stream stattdessen Referenzen (ein Symbol-Link) darauf sein werden. Die Referenz ist ein nullindizierter 32-Bit-Wert (daher ist das erste Vorkommen von :hello 0).

Nach dem Typ-Byte folgt eine Byte-Sequenz, die aus einem Long besteht, der die Anzahl der Bytes in der Sequenz angibt, gefolgt von dieser Anzahl von Datenbytes. Byte-Sequenzen haben keine Kodierung.

Zum Beispiel enthält der folgende Stream das Symbol :hello

"\x04\x08:\x0ahello"

„;“ steht für einen Symbol-Link, der sich auf ein zuvor definiertes Symbol bezieht. Nach dem Typ-Byte folgt ein Long mit dem Index in der Nachschlagetabelle für das verlinkte (referenzierte) Symbol.

Zum Beispiel enthält der folgende Stream [:hello, :hello]

"\x04\b[\a:\nhello;\x00"

Wenn im Folgenden auf ein „Symbol“ Bezug genommen wird, kann es sich entweder um ein echtes Symbol oder um einen Symbol-Link handeln.

Objekt-Referenzen

Getrennt von, aber ähnlich wie Symbol-Referenzen, enthält der Stream nur eine Kopie jedes Objekts (bestimmt durch object_id) für alle Objekte außer true, false, nil, Fixnums und Symbolen (die separat wie oben beschrieben gespeichert werden). Ein einindizierter 32-Bit-Wert wird gespeichert und wiederverwendet, wenn das Objekt erneut angetroffen wird. (Das erste Objekt hat einen Index von 1).

„@“ steht für einen Objekt-Link. Nach dem Typ-Byte folgt ein Long, der den Index des Objekts angibt.

Zum Beispiel enthält der folgende Stream ein Array desselben "hello"-Objekts zweimal

"\004\b[\a\"\nhello@\006"

Instanzvariablen

„I“ gibt an, dass Instanzvariablen dem nächsten Objekt folgen. Ein Objekt folgt dem Typ-Byte. Nach dem Objekt folgt eine Länge, die die Anzahl der Instanzvariablen für das Objekt angibt. Nach der Länge folgt eine Reihe von Namen-Wert-Paaren. Die Namen sind Symbole, während die Werte Objekte sind. Die Symbole müssen Instanzvariablennamen sein (:@name).

Ein Objekt (Typ „o“, siehe unten) verwendet das gleiche Format für seine Instanzvariablen wie hier beschrieben.

Für einen String und ein Regexp (siehe unten) wird eine spezielle Instanzvariable :E verwendet, um die Encoding anzugeben.

Erweitert

„e“ gibt an, dass das nächste Objekt durch ein Modul erweitert wird. Ein Objekt folgt dem Typ-Byte. Nach dem Objekt folgt ein Symbol, das den Namen des Moduls enthält, durch das das Objekt erweitert wird.

Array

„[“ steht für ein Array. Nach dem Typ-Byte folgt ein Long, der die Anzahl der Objekte im Array angibt. Die angegebene Anzahl von Objekten folgt der Länge.

Bignum

„l“ steht für eine Bignum, die aus drei Teilen besteht

sign

Ein einzelnes Byte mit „+“ für einen positiven Wert oder „-“ für einen negativen Wert.

Länge

Ein Long, der die Anzahl der Bytes der Bignum-Daten angibt, geteilt durch zwei. Multiplizieren Sie die Länge mit zwei, um die Anzahl der folgenden Datenbytes zu ermitteln.

Daten

Bytes von Bignum-Daten, die die Zahl darstellen.

Der folgende Ruby-Code wird den Bignum-Wert aus einem Array von Bytes rekonstruieren

result = 0

bytes.each_with_index do |byte, exp|
 result += (byte * 2 ** (exp * 8))
end

Klasse und Modul

„c“ steht für ein Class-Objekt, „m“ für ein Module und „M“ für entweder eine Klasse oder ein Modul (dies ist ein alter Stil zur Kompatibilität). Kein Klassen- oder Modulinhalt ist enthalten, dieser Typ ist nur eine Referenz. Nach dem Typ-Byte folgt eine Byte-Sequenz, die zum Nachschlagen einer vorhandenen Klasse oder eines Moduls verwendet wird.

Instanzvariablen sind für Klassen oder Module nicht zulässig.

Wenn keine Klasse oder kein Modul existiert, sollte eine Ausnahme ausgelöst werden.

Für die Typen „c“ und „m“ muss das geladene Objekt eine Klasse bzw. ein Modul sein.

Data

„d“ steht für ein Data-Objekt. (Data-Objekte sind umwickelte Zeiger aus Ruby-Erweiterungen.) Nach dem Typ-Byte folgt ein Symbol, das die Klasse für das Data-Objekt angibt, und ein Objekt, das den Zustand des Data-Objekts enthält.

Zum Ablegen eines Data-Objekts ruft Ruby _dump_data auf. Zum Laden eines Data-Objekts ruft Ruby _load_data mit dem Zustand des Objekts auf einer neu zugewiesenen Instanz auf.

Float

„f“ steht für ein Float-Objekt. Nach dem Typ-Byte folgt eine Byte-Sequenz, die den Float-Wert enthält. Die folgenden Werte sind speziell

“inf”

Positive Unendlichkeit

“-inf”

Negative Unendlichkeit

“nan”

Keine Zahl

Andernfalls enthält die Byte-Sequenz ein C double (ladbar mit strtod(3)). Frühere Nebenversionen von Marshal speicherten auch zusätzliche Mantissenbits, um die Portabilität zwischen Plattformen zu gewährleisten, aber 4.8 enthält diese nicht. Siehe

ruby-talk:69518

für einige Erklärungen.

Hash und Hash mit Standardwert

„{“ steht für ein Hash-Objekt, während „}“ für ein Hash mit einem gesetzten Standardwert steht (Hash.new 0). Nach dem Typ-Byte folgt ein Long, der die Anzahl der Schlüssel-Wert-Paare im Hash angibt, die Größe. Die doppelte Anzahl der Objekte folgt der Größe.

Für einen Hash mit einem Standardwert folgt der Standardwert allen Paaren.

Modul und altes Modul

Objekt

„o“ steht für ein Objekt, das keine andere spezielle Form hat (wie z. B. ein benutzerdefiniertes oder integriertes Format). Nach dem Typ-Byte folgt ein Symbol, das den Klassennamen des Objekts enthält. Nach dem Klassennamen folgt ein Long, der die Anzahl der Instanzvariablennamen und Werte für das Objekt angibt. Das Doppelte der angegebenen Anzahl von Paaren von Objekten folgt der Größe.

Die Schlüssel in den Paaren müssen Symbole sein, die Instanzvariablennamen enthalten.

Regulärer Ausdruck

„/“ steht für einen regulären Ausdruck. Nach dem Typ-Byte folgt eine Byte-Sequenz, die den Quellcode des regulären Ausdrucks enthält. Nach dem Typ-Byte folgt ein Byte, das die Optionen des regulären Ausdrucks (Groß-/Kleinschreibung ignorieren usw.) als vorzeichenbehafteten 8-Bit-Wert enthält.

Reguläre Ausdrücke können eine Kodierung über Instanzvariablen haben (siehe oben). Wenn keine Kodierung angehängt ist, müssen Escape-Sequenzen für die folgenden regulären Ausdrucksspezialitäten, die in Ruby 1.8 nicht vorhanden sind, entfernt werden: g-m, o-q, u, y, E, F, H-L, N-V, X, Y.

String

„"“ steht für einen String. Nach dem Typ-Byte folgt eine Byte-Sequenz, die den String-Inhalt enthält. Wenn er von Ruby 1.9 abgeleitet wird, sollte eine Kodierungs-Instanzvariable (:E, siehe oben) enthalten sein, es sei denn, die Kodierung ist binär.

Struct

„S“ steht für eine Struct. Nach dem Typ-Byte folgt ein Symbol, das den Namen der Struktur enthält. Nach dem Namen folgt ein Long, der die Anzahl der Mitglieder in der Struktur angibt. Das Doppelte der Anzahl der Objekte folgt der Mitgliederanzahl. Jedes Mitglied ist ein Paar, das das Symbol des Mitglieds und ein Objekt für den Wert dieses Mitglieds enthält.

Wenn der Strukturname nicht mit einer Struct-Unterklasse im laufenden Ruby übereinstimmt, sollte eine Ausnahme ausgelöst werden.

Wenn es eine Diskrepanz zwischen der Struktur im aktuell laufenden Ruby und der Mitgliederanzahl in der marshalierten Struktur gibt, sollte eine Ausnahme ausgelöst werden.

Benutzerdefinierte Klasse

„C“ steht für eine Unterklasse eines String, Regexp, Array oder Hash. Nach dem Typ-Byte folgt ein Symbol, das den Namen der Unterklasse enthält. Nach dem Namen folgt das umwickelte Objekt.

Benutzerdefiniert

„u“ steht für ein Objekt mit einem benutzerdefinierten Serialisierungsformat, das die Instanzmethode _dump und die Klassenmethode _load verwendet. Nach dem Typ-Byte folgt ein Symbol, das den Klassennamen enthält. Nach dem Klassennamen folgt eine Byte-Sequenz, die die benutzerdefinierte Darstellung des Objekts enthält.

Die Klassenmethode _load wird auf der Klasse mit einem aus der Byte-Sequenz erstellten String aufgerufen.

Dieser Typ wird für neu erstellte Klassen nicht empfohlen, da er einige Einschränkungen hat

Benutzerdefiniertes Marshal

„U“ steht für ein Objekt mit einem benutzerdefinierten Serialisierungsformat, das die Instanzmethoden marshal_dump und marshal_load verwendet. Nach dem Typ-Byte folgt ein Symbol, das den Klassennamen enthält. Nach dem Klassennamen folgt ein Objekt, das die Daten enthält.

Beim Laden muss eine neue Instanz zugewiesen und marshal_load auf der Instanz mit den Daten aufgerufen werden.