1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
require_relative 'extension'
module Puppet::Pops
module Serialization
# The serializer is capable of writing, arrays, maps, and complex objects using an underlying protocol writer. It takes care of
# tabulating and disassembling complex objects.
# @api public
class Serializer
# Provides access to the writer.
# @api private
attr_reader :writer
# @param writer [AbstractWriter] the writer that is used for writing primitive values
# @param options [{String, Object}] serialization options
# @option options [Boolean] :type_by_reference `true` if Object types are serialized by name only.
# @api public
def initialize(writer, options = EMPTY_HASH)
@written = {}
@writer = writer
@options = options
end
# Tell the underlying writer to finish
# @api public
def finish
@writer.finish
end
# Write an object
# @param [Object] value the object to write
# @api public
def write(value)
case value
when Integer, Float, String, true, false, nil
@writer.write(value)
when :default
@writer.write(Extension::Default::INSTANCE)
else
index = @written[value.object_id]
if index.nil?
write_tabulated_first_time(value)
else
@writer.write(Extension::Tabulation.new(index))
end
end
end
# Write the start of an array.
# @param [Integer] size the size of the array
# @api private
def start_array(size)
@writer.write(Extension::ArrayStart.new(size))
end
# Write the start of a map (hash).
# @param [Integer] size the number of entries in the map
# @api private
def start_map(size)
@writer.write(Extension::MapStart.new(size))
end
# Write the start of a complex pcore object
# @param [String] type_ref the name of the type
# @param [Integer] attr_count the number of attributes in the object
# @api private
def start_pcore_object(type_ref, attr_count)
@writer.write(Extension::PcoreObjectStart.new(type_ref, attr_count))
end
# Write the start of a complex object
# @param [Integer] attr_count the number of attributes in the object
# @api private
def start_object(attr_count)
@writer.write(Extension::ObjectStart.new(attr_count))
end
def push_written(value)
@written[value.object_id] = @written.size
end
# Write the start of a sensitive object
# @api private
def start_sensitive
@writer.write(Extension::SensitiveStart::INSTANCE)
end
def type_by_reference?
@options[:type_by_reference] == true
end
def to_s
"#{self.class.name} with #{@writer}"
end
def inspect
to_s
end
# First time write of a tabulated object. This means that the object is written and then remembered. Subsequent writes
# of the same object will yield a write of a tabulation index instead.
# @param [Object] value the value to write
# @api private
def write_tabulated_first_time(value)
case
when value.instance_of?(Symbol),
value.instance_of?(Regexp),
value.instance_of?(SemanticPuppet::Version),
value.instance_of?(SemanticPuppet::VersionRange),
value.instance_of?(Time::Timestamp),
value.instance_of?(Time::Timespan),
value.instance_of?(Types::PBinaryType::Binary),
value.is_a?(URI)
push_written(value)
@writer.write(value)
when value.instance_of?(Array)
push_written(value)
start_array(value.size)
value.each { |elem| write(elem) }
when value.instance_of?(Hash)
push_written(value)
start_map(value.size)
value.each_pair { |key, val| write(key); write(val) }
when value.instance_of?(Types::PSensitiveType::Sensitive)
start_sensitive
write(value.unwrap)
when value.instance_of?(Types::PTypeReferenceType)
push_written(value)
@writer.write(value)
when value.is_a?(Types::PuppetObject)
value._pcore_type.write(value, self)
else
impl_class = value.class
type = Loaders.implementation_registry.type_for_module(impl_class)
raise SerializationError, _("No Puppet Type found for %{klass}") % { klass: impl_class.name } unless type.is_a?(Types::PObjectType)
type.write(value, self)
end
end
end
end
end
|