# frozen_string_literal: true module LIT # @api public # @since 0.1.0 class Serializer def initialize(object) @object = object end def serialize serialize_object(@object) end private # rubocop:disable Metrics/MethodLength def serialize_object(object) if object.is_a?(Object::Struct) if object.is_a?(Object::EnumVariant) serialize_enum_variant(object) else serialize_struct(object) end elsif object.is_a?(Module) && object <= Object::EnumVariant serialize_enum_variant(object) elsif object.is_a?(Object::Array) serialize_array(object) elsif object.is_a?(Object::Map) serialize_map(object) elsif object.is_a?(Object::Option::Some) || object == Object::Option::None serialize_option(object) elsif object.is_a?(String) || object.is_a?(Integer) || object.is_a?(Float) || object == true || object == false || object.nil? object else raise InvalidObjectError, "invalid object: #{object}" end end # rubocop:enable Metrics/MethodLength def serialize_struct(struct) struct.instance_variables.reduce({}) do |hsh, ivar| field_name = ivar.to_s.sub("@", "").to_sym hsh.merge(field_name => serialize_object(struct.public_send(field_name))) end end def serialize_enum_variant(variant) data = if variant.__kind__ == :struct serialize_struct(variant) else nil end { kind: variant.__name__, data: data } end def serialize_array(array) array.__values__.map { |value| serialize_object(value) } end def serialize_map(map) map.__values__.reduce({}) do |acc, (key, value)| acc.merge(serialize_object(key) => serialize_object(value)) end end def serialize_option(option) if option == Object::Option::None nil else serialize_object(option.__value__) end end end end