/*----------------------------------------------------------------------------*/
/* This file is generated by the templates/template.rb script and should not  */
/* be modified manually.                                                      */
/* To change the template see                                                 */
/* templates/src/serialize.c.erb                                              */
/*----------------------------------------------------------------------------*/

#include "rbs/serialize.h"

#include "rbs/location.h"
#include "rbs/util/rbs_assert.h"
#include "rbs/util/rbs_buffer.h"

#include <stdint.h>

/**
 * State threaded through the recursive serializer: the arena the output buffer
 * grows in, the constant pool used to resolve interned ids, and the buffer
 * itself.
 */
typedef struct {
    rbs_allocator_t *allocator;
    rbs_constant_pool_t *constant_pool;
    rbs_buffer_t buffer;
} rbs_serialize_state;

/* All multi-byte integers are written little-endian. */

static void w_bytes(rbs_serialize_state *state, const char *value, size_t length) {
    if (length > 0) {
        rbs_buffer_append_string(state->allocator, &state->buffer, value, length);
    }
}

static void w_u8(rbs_serialize_state *state, uint8_t value) {
    w_bytes(state, (const char *) &value, 1);
}

static void w_u32(rbs_serialize_state *state, uint32_t value) {
    unsigned char bytes[4] = {
        (unsigned char) (value & 0xff),
        (unsigned char) ((value >> 8) & 0xff),
        (unsigned char) ((value >> 16) & 0xff),
        (unsigned char) ((value >> 24) & 0xff),
    };
    w_bytes(state, (const char *) bytes, 4);
}

static void w_i32(rbs_serialize_state *state, int32_t value) {
    w_u32(state, (uint32_t) value);
}

static void w_string(rbs_serialize_state *state, rbs_string_t string) {
    size_t length = rbs_string_len(string);
    w_u32(state, (uint32_t) length);
    w_bytes(state, string.start, length);
}

static void w_constant(rbs_serialize_state *state, rbs_constant_id_t id) {
    rbs_constant_t *constant = rbs_constant_pool_id_to_constant(state->constant_pool, id);
    RBS_ASSERT(constant != NULL, "constant is NULL");
    w_u32(state, (uint32_t) constant->length);
    w_bytes(state, (const char *) constant->start, constant->length);
}

// A location range is encoded as a presence byte, followed by the start/end
// character positions when present. A null range encodes as a single 0 byte
// (it becomes `nil` on the Ruby side).
static void w_loc_range(rbs_serialize_state *state, rbs_location_range range) {
    if (RBS_LOCATION_NULL_RANGE_P(range)) {
        w_u8(state, 0);
    } else {
        w_u8(state, 1);
        w_i32(state, range.start_char);
        w_i32(state, range.end_char);
    }
}

static void w_loc_range_list(rbs_serialize_state *state, rbs_location_range_list_t *list) {
    if (list == NULL) {
        w_u32(state, 0);
        return;
    }

    w_u32(state, (uint32_t) list->length);
    for (rbs_location_range_list_node_t *n = list->head; n != NULL; n = n->next) {
        w_loc_range(state, n->range);
    }
}

static void w_attr_ivar_name(rbs_serialize_state *state, rbs_attr_ivar_name_t ivar_name) {
    w_u8(state, (uint8_t) ivar_name.tag);
    if (ivar_name.tag == RBS_ATTR_IVAR_NAME_TAG_NAME) {
        w_constant(state, ivar_name.name);
    }
}

static void serialize_node(rbs_serialize_state *state, rbs_node_t *instance);

static void w_node_list(rbs_serialize_state *state, rbs_node_list_t *list) {
    if (list == NULL) {
        w_u32(state, 0);
        return;
    }

    w_u32(state, (uint32_t) list->length);
    for (rbs_node_list_node_t *n = list->head; n != NULL; n = n->next) {
        serialize_node(state, n->node);
    }
}

static void w_hash(rbs_serialize_state *state, rbs_hash_t *hash) {
    if (hash == NULL) {
        w_u32(state, 0);
        return;
    }

    // rbs_hash_t does not maintain its `length` field (unlike rbs_node_list_t),
    // so count the entries by walking the list.
    uint32_t count = 0;
    for (rbs_hash_node_t *n = hash->head; n != NULL; n = n->next) {
        count++;
    }
    w_u32(state, count);

    for (rbs_hash_node_t *n = hash->head; n != NULL; n = n->next) {
        serialize_node(state, n->key);
        serialize_node(state, n->value);
    }
}

// The node tag written ahead of every node. Tag 0 is reserved for NULL, tags
// 1..N are the nodes below (in the same order the Ruby schema is generated),
// and the final tag is `rbs_ast_symbol`, which is not a config.yml node.
#define RBS_SERIALIZE_TAG_SYMBOL 79

static void serialize_node(rbs_serialize_state *state, rbs_node_t *instance) {
    if (instance == NULL) {
        w_u8(state, 0);
        return;
    }

    switch (instance->type) {
    case RBS_AST_ANNOTATION: {
        w_u8(state, 1);
        rbs_ast_annotation_t *node = (rbs_ast_annotation_t *) instance;
        w_loc_range(state, node->base.location);
        w_string(state, node->string);
        return;
    }
    case RBS_AST_BOOL: {
        w_u8(state, 2);
        w_u8(state, ((rbs_ast_bool_t *) instance)->value ? 1 : 0);
        return;
    }
    case RBS_AST_COMMENT: {
        w_u8(state, 3);
        rbs_ast_comment_t *node = (rbs_ast_comment_t *) instance;
        w_loc_range(state, node->base.location);
        w_string(state, node->string);
        return;
    }
    case RBS_AST_DECLARATIONS_CLASS: {
        w_u8(state, 4);
        rbs_ast_declarations_class_t *node = (rbs_ast_declarations_class_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->keyword_range);
        w_loc_range(state, node->name_range);
        w_loc_range(state, node->end_range);
        w_loc_range(state, node->type_params_range);
        w_loc_range(state, node->lt_range);
        serialize_node(state, (rbs_node_t *) node->name);
        w_node_list(state, node->type_params);
        serialize_node(state, (rbs_node_t *) node->super_class);
        w_node_list(state, node->members);
        w_node_list(state, node->annotations);
        serialize_node(state, (rbs_node_t *) node->comment);
        return;
    }
    case RBS_AST_DECLARATIONS_CLASS_SUPER: {
        w_u8(state, 5);
        rbs_ast_declarations_class_super_t *node = (rbs_ast_declarations_class_super_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->name_range);
        w_loc_range(state, node->args_range);
        serialize_node(state, (rbs_node_t *) node->name);
        w_node_list(state, node->args);
        return;
    }
    case RBS_AST_DECLARATIONS_CLASS_ALIAS: {
        w_u8(state, 6);
        rbs_ast_declarations_class_alias_t *node = (rbs_ast_declarations_class_alias_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->keyword_range);
        w_loc_range(state, node->new_name_range);
        w_loc_range(state, node->eq_range);
        w_loc_range(state, node->old_name_range);
        serialize_node(state, (rbs_node_t *) node->new_name);
        serialize_node(state, (rbs_node_t *) node->old_name);
        serialize_node(state, (rbs_node_t *) node->comment);
        w_node_list(state, node->annotations);
        return;
    }
    case RBS_AST_DECLARATIONS_CONSTANT: {
        w_u8(state, 7);
        rbs_ast_declarations_constant_t *node = (rbs_ast_declarations_constant_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->name_range);
        w_loc_range(state, node->colon_range);
        serialize_node(state, (rbs_node_t *) node->name);
        serialize_node(state, (rbs_node_t *) node->type);
        serialize_node(state, (rbs_node_t *) node->comment);
        w_node_list(state, node->annotations);
        return;
    }
    case RBS_AST_DECLARATIONS_GLOBAL: {
        w_u8(state, 8);
        rbs_ast_declarations_global_t *node = (rbs_ast_declarations_global_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->name_range);
        w_loc_range(state, node->colon_range);
        serialize_node(state, (rbs_node_t *) node->name);
        serialize_node(state, (rbs_node_t *) node->type);
        serialize_node(state, (rbs_node_t *) node->comment);
        w_node_list(state, node->annotations);
        return;
    }
    case RBS_AST_DECLARATIONS_INTERFACE: {
        w_u8(state, 9);
        rbs_ast_declarations_interface_t *node = (rbs_ast_declarations_interface_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->keyword_range);
        w_loc_range(state, node->name_range);
        w_loc_range(state, node->end_range);
        w_loc_range(state, node->type_params_range);
        serialize_node(state, (rbs_node_t *) node->name);
        w_node_list(state, node->type_params);
        w_node_list(state, node->members);
        w_node_list(state, node->annotations);
        serialize_node(state, (rbs_node_t *) node->comment);
        return;
    }
    case RBS_AST_DECLARATIONS_MODULE: {
        w_u8(state, 10);
        rbs_ast_declarations_module_t *node = (rbs_ast_declarations_module_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->keyword_range);
        w_loc_range(state, node->name_range);
        w_loc_range(state, node->end_range);
        w_loc_range(state, node->type_params_range);
        w_loc_range(state, node->colon_range);
        w_loc_range(state, node->self_types_range);
        serialize_node(state, (rbs_node_t *) node->name);
        w_node_list(state, node->type_params);
        w_node_list(state, node->self_types);
        w_node_list(state, node->members);
        w_node_list(state, node->annotations);
        serialize_node(state, (rbs_node_t *) node->comment);
        return;
    }
    case RBS_AST_DECLARATIONS_MODULE_SELF: {
        w_u8(state, 11);
        rbs_ast_declarations_module_self_t *node = (rbs_ast_declarations_module_self_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->name_range);
        w_loc_range(state, node->args_range);
        serialize_node(state, (rbs_node_t *) node->name);
        w_node_list(state, node->args);
        return;
    }
    case RBS_AST_DECLARATIONS_MODULE_ALIAS: {
        w_u8(state, 12);
        rbs_ast_declarations_module_alias_t *node = (rbs_ast_declarations_module_alias_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->keyword_range);
        w_loc_range(state, node->new_name_range);
        w_loc_range(state, node->eq_range);
        w_loc_range(state, node->old_name_range);
        serialize_node(state, (rbs_node_t *) node->new_name);
        serialize_node(state, (rbs_node_t *) node->old_name);
        serialize_node(state, (rbs_node_t *) node->comment);
        w_node_list(state, node->annotations);
        return;
    }
    case RBS_AST_DECLARATIONS_TYPE_ALIAS: {
        w_u8(state, 13);
        rbs_ast_declarations_type_alias_t *node = (rbs_ast_declarations_type_alias_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->keyword_range);
        w_loc_range(state, node->name_range);
        w_loc_range(state, node->eq_range);
        w_loc_range(state, node->type_params_range);
        serialize_node(state, (rbs_node_t *) node->name);
        w_node_list(state, node->type_params);
        serialize_node(state, (rbs_node_t *) node->type);
        w_node_list(state, node->annotations);
        serialize_node(state, (rbs_node_t *) node->comment);
        return;
    }
    case RBS_AST_DIRECTIVES_USE: {
        w_u8(state, 14);
        rbs_ast_directives_use_t *node = (rbs_ast_directives_use_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->keyword_range);
        w_node_list(state, node->clauses);
        return;
    }
    case RBS_AST_DIRECTIVES_USE_SINGLE_CLAUSE: {
        w_u8(state, 15);
        rbs_ast_directives_use_single_clause_t *node = (rbs_ast_directives_use_single_clause_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->type_name_range);
        w_loc_range(state, node->keyword_range);
        w_loc_range(state, node->new_name_range);
        serialize_node(state, (rbs_node_t *) node->type_name);
        serialize_node(state, (rbs_node_t *) node->new_name);
        return;
    }
    case RBS_AST_DIRECTIVES_USE_WILDCARD_CLAUSE: {
        w_u8(state, 16);
        rbs_ast_directives_use_wildcard_clause_t *node = (rbs_ast_directives_use_wildcard_clause_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->namespace_range);
        w_loc_range(state, node->star_range);
        serialize_node(state, (rbs_node_t *) node->rbs_namespace);
        return;
    }
    case RBS_AST_INTEGER: {
        w_u8(state, 17);
        w_string(state, ((rbs_ast_integer_t *) instance)->string_representation);
        return;
    }
    case RBS_AST_MEMBERS_ALIAS: {
        w_u8(state, 18);
        rbs_ast_members_alias_t *node = (rbs_ast_members_alias_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->keyword_range);
        w_loc_range(state, node->new_name_range);
        w_loc_range(state, node->old_name_range);
        w_loc_range(state, node->new_kind_range);
        w_loc_range(state, node->old_kind_range);
        serialize_node(state, (rbs_node_t *) node->new_name);
        serialize_node(state, (rbs_node_t *) node->old_name);
        w_u8(state, (uint8_t) node->kind);
        w_node_list(state, node->annotations);
        serialize_node(state, (rbs_node_t *) node->comment);
        return;
    }
    case RBS_AST_MEMBERS_ATTR_ACCESSOR: {
        w_u8(state, 19);
        rbs_ast_members_attr_accessor_t *node = (rbs_ast_members_attr_accessor_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->keyword_range);
        w_loc_range(state, node->name_range);
        w_loc_range(state, node->colon_range);
        w_loc_range(state, node->kind_range);
        w_loc_range(state, node->ivar_range);
        w_loc_range(state, node->ivar_name_range);
        w_loc_range(state, node->visibility_range);
        serialize_node(state, (rbs_node_t *) node->name);
        serialize_node(state, (rbs_node_t *) node->type);
        w_attr_ivar_name(state, node->ivar_name);
        w_u8(state, (uint8_t) node->kind);
        w_node_list(state, node->annotations);
        serialize_node(state, (rbs_node_t *) node->comment);
        w_u8(state, (uint8_t) node->visibility);
        return;
    }
    case RBS_AST_MEMBERS_ATTR_READER: {
        w_u8(state, 20);
        rbs_ast_members_attr_reader_t *node = (rbs_ast_members_attr_reader_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->keyword_range);
        w_loc_range(state, node->name_range);
        w_loc_range(state, node->colon_range);
        w_loc_range(state, node->kind_range);
        w_loc_range(state, node->ivar_range);
        w_loc_range(state, node->ivar_name_range);
        w_loc_range(state, node->visibility_range);
        serialize_node(state, (rbs_node_t *) node->name);
        serialize_node(state, (rbs_node_t *) node->type);
        w_attr_ivar_name(state, node->ivar_name);
        w_u8(state, (uint8_t) node->kind);
        w_node_list(state, node->annotations);
        serialize_node(state, (rbs_node_t *) node->comment);
        w_u8(state, (uint8_t) node->visibility);
        return;
    }
    case RBS_AST_MEMBERS_ATTR_WRITER: {
        w_u8(state, 21);
        rbs_ast_members_attr_writer_t *node = (rbs_ast_members_attr_writer_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->keyword_range);
        w_loc_range(state, node->name_range);
        w_loc_range(state, node->colon_range);
        w_loc_range(state, node->kind_range);
        w_loc_range(state, node->ivar_range);
        w_loc_range(state, node->ivar_name_range);
        w_loc_range(state, node->visibility_range);
        serialize_node(state, (rbs_node_t *) node->name);
        serialize_node(state, (rbs_node_t *) node->type);
        w_attr_ivar_name(state, node->ivar_name);
        w_u8(state, (uint8_t) node->kind);
        w_node_list(state, node->annotations);
        serialize_node(state, (rbs_node_t *) node->comment);
        w_u8(state, (uint8_t) node->visibility);
        return;
    }
    case RBS_AST_MEMBERS_CLASS_INSTANCE_VARIABLE: {
        w_u8(state, 22);
        rbs_ast_members_class_instance_variable_t *node = (rbs_ast_members_class_instance_variable_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->name_range);
        w_loc_range(state, node->colon_range);
        w_loc_range(state, node->kind_range);
        serialize_node(state, (rbs_node_t *) node->name);
        serialize_node(state, (rbs_node_t *) node->type);
        serialize_node(state, (rbs_node_t *) node->comment);
        return;
    }
    case RBS_AST_MEMBERS_CLASS_VARIABLE: {
        w_u8(state, 23);
        rbs_ast_members_class_variable_t *node = (rbs_ast_members_class_variable_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->name_range);
        w_loc_range(state, node->colon_range);
        w_loc_range(state, node->kind_range);
        serialize_node(state, (rbs_node_t *) node->name);
        serialize_node(state, (rbs_node_t *) node->type);
        serialize_node(state, (rbs_node_t *) node->comment);
        return;
    }
    case RBS_AST_MEMBERS_EXTEND: {
        w_u8(state, 24);
        rbs_ast_members_extend_t *node = (rbs_ast_members_extend_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->name_range);
        w_loc_range(state, node->keyword_range);
        w_loc_range(state, node->args_range);
        serialize_node(state, (rbs_node_t *) node->name);
        w_node_list(state, node->args);
        w_node_list(state, node->annotations);
        serialize_node(state, (rbs_node_t *) node->comment);
        return;
    }
    case RBS_AST_MEMBERS_INCLUDE: {
        w_u8(state, 25);
        rbs_ast_members_include_t *node = (rbs_ast_members_include_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->name_range);
        w_loc_range(state, node->keyword_range);
        w_loc_range(state, node->args_range);
        serialize_node(state, (rbs_node_t *) node->name);
        w_node_list(state, node->args);
        w_node_list(state, node->annotations);
        serialize_node(state, (rbs_node_t *) node->comment);
        return;
    }
    case RBS_AST_MEMBERS_INSTANCE_VARIABLE: {
        w_u8(state, 26);
        rbs_ast_members_instance_variable_t *node = (rbs_ast_members_instance_variable_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->name_range);
        w_loc_range(state, node->colon_range);
        w_loc_range(state, node->kind_range);
        serialize_node(state, (rbs_node_t *) node->name);
        serialize_node(state, (rbs_node_t *) node->type);
        serialize_node(state, (rbs_node_t *) node->comment);
        return;
    }
    case RBS_AST_MEMBERS_METHOD_DEFINITION: {
        w_u8(state, 27);
        rbs_ast_members_method_definition_t *node = (rbs_ast_members_method_definition_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->keyword_range);
        w_loc_range(state, node->name_range);
        w_loc_range(state, node->kind_range);
        w_loc_range(state, node->overloading_range);
        w_loc_range(state, node->visibility_range);
        serialize_node(state, (rbs_node_t *) node->name);
        w_u8(state, (uint8_t) node->kind);
        w_node_list(state, node->overloads);
        w_node_list(state, node->annotations);
        serialize_node(state, (rbs_node_t *) node->comment);
        w_u8(state, node->overloading ? 1 : 0);
        w_u8(state, (uint8_t) node->visibility);
        return;
    }
    case RBS_AST_MEMBERS_METHOD_DEFINITION_OVERLOAD: {
        w_u8(state, 28);
        rbs_ast_members_method_definition_overload_t *node = (rbs_ast_members_method_definition_overload_t *) instance;
        w_node_list(state, node->annotations);
        serialize_node(state, (rbs_node_t *) node->method_type);
        return;
    }
    case RBS_AST_MEMBERS_PREPEND: {
        w_u8(state, 29);
        rbs_ast_members_prepend_t *node = (rbs_ast_members_prepend_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->name_range);
        w_loc_range(state, node->keyword_range);
        w_loc_range(state, node->args_range);
        serialize_node(state, (rbs_node_t *) node->name);
        w_node_list(state, node->args);
        w_node_list(state, node->annotations);
        serialize_node(state, (rbs_node_t *) node->comment);
        return;
    }
    case RBS_AST_MEMBERS_PRIVATE: {
        w_u8(state, 30);
        rbs_ast_members_private_t *node = (rbs_ast_members_private_t *) instance;
        w_loc_range(state, node->base.location);
        return;
    }
    case RBS_AST_MEMBERS_PUBLIC: {
        w_u8(state, 31);
        rbs_ast_members_public_t *node = (rbs_ast_members_public_t *) instance;
        w_loc_range(state, node->base.location);
        return;
    }
    case RBS_AST_RUBY_ANNOTATIONS_BLOCK_PARAM_TYPE_ANNOTATION: {
        w_u8(state, 32);
        rbs_ast_ruby_annotations_block_param_type_annotation_t *node = (rbs_ast_ruby_annotations_block_param_type_annotation_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->prefix_location);
        w_loc_range(state, node->ampersand_location);
        w_loc_range(state, node->name_location);
        w_loc_range(state, node->colon_location);
        w_loc_range(state, node->question_location);
        w_loc_range(state, node->type_location);
        serialize_node(state, (rbs_node_t *) node->type_);
        w_loc_range(state, node->comment_location);
        return;
    }
    case RBS_AST_RUBY_ANNOTATIONS_CLASS_ALIAS_ANNOTATION: {
        w_u8(state, 33);
        rbs_ast_ruby_annotations_class_alias_annotation_t *node = (rbs_ast_ruby_annotations_class_alias_annotation_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->prefix_location);
        w_loc_range(state, node->keyword_location);
        serialize_node(state, (rbs_node_t *) node->type_name);
        w_loc_range(state, node->type_name_location);
        return;
    }
    case RBS_AST_RUBY_ANNOTATIONS_COLON_METHOD_TYPE_ANNOTATION: {
        w_u8(state, 34);
        rbs_ast_ruby_annotations_colon_method_type_annotation_t *node = (rbs_ast_ruby_annotations_colon_method_type_annotation_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->prefix_location);
        w_node_list(state, node->annotations);
        serialize_node(state, (rbs_node_t *) node->method_type);
        return;
    }
    case RBS_AST_RUBY_ANNOTATIONS_DOUBLE_SPLAT_PARAM_TYPE_ANNOTATION: {
        w_u8(state, 35);
        rbs_ast_ruby_annotations_double_splat_param_type_annotation_t *node = (rbs_ast_ruby_annotations_double_splat_param_type_annotation_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->prefix_location);
        w_loc_range(state, node->star2_location);
        w_loc_range(state, node->name_location);
        w_loc_range(state, node->colon_location);
        serialize_node(state, (rbs_node_t *) node->param_type);
        w_loc_range(state, node->comment_location);
        return;
    }
    case RBS_AST_RUBY_ANNOTATIONS_INSTANCE_VARIABLE_ANNOTATION: {
        w_u8(state, 36);
        rbs_ast_ruby_annotations_instance_variable_annotation_t *node = (rbs_ast_ruby_annotations_instance_variable_annotation_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->prefix_location);
        serialize_node(state, (rbs_node_t *) node->ivar_name);
        w_loc_range(state, node->ivar_name_location);
        w_loc_range(state, node->colon_location);
        serialize_node(state, (rbs_node_t *) node->type);
        w_loc_range(state, node->comment_location);
        return;
    }
    case RBS_AST_RUBY_ANNOTATIONS_METHOD_TYPES_ANNOTATION: {
        w_u8(state, 37);
        rbs_ast_ruby_annotations_method_types_annotation_t *node = (rbs_ast_ruby_annotations_method_types_annotation_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->prefix_location);
        w_node_list(state, node->overloads);
        w_loc_range_list(state, node->vertical_bar_locations);
        w_loc_range(state, node->dot3_location);
        return;
    }
    case RBS_AST_RUBY_ANNOTATIONS_MODULE_ALIAS_ANNOTATION: {
        w_u8(state, 38);
        rbs_ast_ruby_annotations_module_alias_annotation_t *node = (rbs_ast_ruby_annotations_module_alias_annotation_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->prefix_location);
        w_loc_range(state, node->keyword_location);
        serialize_node(state, (rbs_node_t *) node->type_name);
        w_loc_range(state, node->type_name_location);
        return;
    }
    case RBS_AST_RUBY_ANNOTATIONS_MODULE_SELF_ANNOTATION: {
        w_u8(state, 39);
        rbs_ast_ruby_annotations_module_self_annotation_t *node = (rbs_ast_ruby_annotations_module_self_annotation_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->prefix_location);
        w_loc_range(state, node->keyword_location);
        w_loc_range(state, node->colon_location);
        serialize_node(state, (rbs_node_t *) node->name);
        w_node_list(state, node->args);
        w_loc_range(state, node->open_bracket_location);
        w_loc_range(state, node->close_bracket_location);
        w_loc_range_list(state, node->args_comma_locations);
        w_loc_range(state, node->comment_location);
        return;
    }
    case RBS_AST_RUBY_ANNOTATIONS_NODE_TYPE_ASSERTION: {
        w_u8(state, 40);
        rbs_ast_ruby_annotations_node_type_assertion_t *node = (rbs_ast_ruby_annotations_node_type_assertion_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->prefix_location);
        serialize_node(state, (rbs_node_t *) node->type);
        return;
    }
    case RBS_AST_RUBY_ANNOTATIONS_PARAM_TYPE_ANNOTATION: {
        w_u8(state, 41);
        rbs_ast_ruby_annotations_param_type_annotation_t *node = (rbs_ast_ruby_annotations_param_type_annotation_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->prefix_location);
        w_loc_range(state, node->name_location);
        w_loc_range(state, node->colon_location);
        serialize_node(state, (rbs_node_t *) node->param_type);
        w_loc_range(state, node->comment_location);
        return;
    }
    case RBS_AST_RUBY_ANNOTATIONS_RETURN_TYPE_ANNOTATION: {
        w_u8(state, 42);
        rbs_ast_ruby_annotations_return_type_annotation_t *node = (rbs_ast_ruby_annotations_return_type_annotation_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->prefix_location);
        w_loc_range(state, node->return_location);
        w_loc_range(state, node->colon_location);
        serialize_node(state, (rbs_node_t *) node->return_type);
        w_loc_range(state, node->comment_location);
        return;
    }
    case RBS_AST_RUBY_ANNOTATIONS_SKIP_ANNOTATION: {
        w_u8(state, 43);
        rbs_ast_ruby_annotations_skip_annotation_t *node = (rbs_ast_ruby_annotations_skip_annotation_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->prefix_location);
        w_loc_range(state, node->skip_location);
        w_loc_range(state, node->comment_location);
        return;
    }
    case RBS_AST_RUBY_ANNOTATIONS_SPLAT_PARAM_TYPE_ANNOTATION: {
        w_u8(state, 44);
        rbs_ast_ruby_annotations_splat_param_type_annotation_t *node = (rbs_ast_ruby_annotations_splat_param_type_annotation_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->prefix_location);
        w_loc_range(state, node->star_location);
        w_loc_range(state, node->name_location);
        w_loc_range(state, node->colon_location);
        serialize_node(state, (rbs_node_t *) node->param_type);
        w_loc_range(state, node->comment_location);
        return;
    }
    case RBS_AST_RUBY_ANNOTATIONS_TYPE_APPLICATION_ANNOTATION: {
        w_u8(state, 45);
        rbs_ast_ruby_annotations_type_application_annotation_t *node = (rbs_ast_ruby_annotations_type_application_annotation_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->prefix_location);
        w_node_list(state, node->type_args);
        w_loc_range(state, node->close_bracket_location);
        w_loc_range_list(state, node->comma_locations);
        return;
    }
    case RBS_AST_STRING: {
        w_u8(state, 46);
        w_string(state, ((rbs_ast_string_t *) instance)->string);
        return;
    }
    case RBS_AST_TYPE_PARAM: {
        w_u8(state, 47);
        rbs_ast_type_param_t *node = (rbs_ast_type_param_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->name_range);
        w_loc_range(state, node->variance_range);
        w_loc_range(state, node->unchecked_range);
        w_loc_range(state, node->upper_bound_range);
        w_loc_range(state, node->lower_bound_range);
        w_loc_range(state, node->default_range);
        serialize_node(state, (rbs_node_t *) node->name);
        w_u8(state, (uint8_t) node->variance);
        serialize_node(state, (rbs_node_t *) node->upper_bound);
        serialize_node(state, (rbs_node_t *) node->lower_bound);
        serialize_node(state, (rbs_node_t *) node->default_type);
        w_u8(state, node->unchecked ? 1 : 0);
        return;
    }
    case RBS_METHOD_TYPE: {
        w_u8(state, 48);
        rbs_method_type_t *node = (rbs_method_type_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->type_range);
        w_loc_range(state, node->type_params_range);
        w_node_list(state, node->type_params);
        serialize_node(state, (rbs_node_t *) node->type);
        serialize_node(state, (rbs_node_t *) node->block);
        return;
    }
    case RBS_NAMESPACE: {
        w_u8(state, 49);
        rbs_namespace_t *node = (rbs_namespace_t *) instance;
        w_node_list(state, node->path);
        w_u8(state, node->absolute ? 1 : 0);
        return;
    }
    case RBS_SIGNATURE: {
        w_u8(state, 50);
        rbs_signature_t *node = (rbs_signature_t *) instance;
        w_node_list(state, node->directives);
        w_node_list(state, node->declarations);
        return;
    }
    case RBS_TYPE_NAME: {
        w_u8(state, 51);
        rbs_type_name_t *node = (rbs_type_name_t *) instance;
        serialize_node(state, (rbs_node_t *) node->rbs_namespace);
        serialize_node(state, (rbs_node_t *) node->name);
        return;
    }
    case RBS_TYPES_ALIAS: {
        w_u8(state, 52);
        rbs_types_alias_t *node = (rbs_types_alias_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->name_range);
        w_loc_range(state, node->args_range);
        serialize_node(state, (rbs_node_t *) node->name);
        w_node_list(state, node->args);
        return;
    }
    case RBS_TYPES_BASES_ANY: {
        w_u8(state, 53);
        rbs_types_bases_any_t *node = (rbs_types_bases_any_t *) instance;
        w_loc_range(state, node->base.location);
        w_u8(state, node->todo ? 1 : 0);
        return;
    }
    case RBS_TYPES_BASES_BOOL: {
        w_u8(state, 54);
        rbs_types_bases_bool_t *node = (rbs_types_bases_bool_t *) instance;
        w_loc_range(state, node->base.location);
        return;
    }
    case RBS_TYPES_BASES_BOTTOM: {
        w_u8(state, 55);
        rbs_types_bases_bottom_t *node = (rbs_types_bases_bottom_t *) instance;
        w_loc_range(state, node->base.location);
        return;
    }
    case RBS_TYPES_BASES_CLASS: {
        w_u8(state, 56);
        rbs_types_bases_class_t *node = (rbs_types_bases_class_t *) instance;
        w_loc_range(state, node->base.location);
        return;
    }
    case RBS_TYPES_BASES_INSTANCE: {
        w_u8(state, 57);
        rbs_types_bases_instance_t *node = (rbs_types_bases_instance_t *) instance;
        w_loc_range(state, node->base.location);
        return;
    }
    case RBS_TYPES_BASES_NIL: {
        w_u8(state, 58);
        rbs_types_bases_nil_t *node = (rbs_types_bases_nil_t *) instance;
        w_loc_range(state, node->base.location);
        return;
    }
    case RBS_TYPES_BASES_SELF: {
        w_u8(state, 59);
        rbs_types_bases_self_t *node = (rbs_types_bases_self_t *) instance;
        w_loc_range(state, node->base.location);
        return;
    }
    case RBS_TYPES_BASES_TOP: {
        w_u8(state, 60);
        rbs_types_bases_top_t *node = (rbs_types_bases_top_t *) instance;
        w_loc_range(state, node->base.location);
        return;
    }
    case RBS_TYPES_BASES_VOID: {
        w_u8(state, 61);
        rbs_types_bases_void_t *node = (rbs_types_bases_void_t *) instance;
        w_loc_range(state, node->base.location);
        return;
    }
    case RBS_TYPES_BLOCK: {
        w_u8(state, 62);
        rbs_types_block_t *node = (rbs_types_block_t *) instance;
        w_loc_range(state, node->base.location);
        serialize_node(state, (rbs_node_t *) node->type);
        w_u8(state, node->required ? 1 : 0);
        serialize_node(state, (rbs_node_t *) node->self_type);
        return;
    }
    case RBS_TYPES_CLASS_INSTANCE: {
        w_u8(state, 63);
        rbs_types_class_instance_t *node = (rbs_types_class_instance_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->name_range);
        w_loc_range(state, node->args_range);
        serialize_node(state, (rbs_node_t *) node->name);
        w_node_list(state, node->args);
        return;
    }
    case RBS_TYPES_CLASS_SINGLETON: {
        w_u8(state, 64);
        rbs_types_class_singleton_t *node = (rbs_types_class_singleton_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->name_range);
        w_loc_range(state, node->args_range);
        serialize_node(state, (rbs_node_t *) node->name);
        w_node_list(state, node->args);
        return;
    }
    case RBS_TYPES_FUNCTION: {
        w_u8(state, 65);
        rbs_types_function_t *node = (rbs_types_function_t *) instance;
        w_node_list(state, node->required_positionals);
        w_node_list(state, node->optional_positionals);
        serialize_node(state, (rbs_node_t *) node->rest_positionals);
        w_node_list(state, node->trailing_positionals);
        w_hash(state, node->required_keywords);
        w_hash(state, node->optional_keywords);
        serialize_node(state, (rbs_node_t *) node->rest_keywords);
        serialize_node(state, (rbs_node_t *) node->forwarding);
        serialize_node(state, (rbs_node_t *) node->return_type);
        return;
    }
    case RBS_TYPES_FUNCTION_FORWARDING_PARAM: {
        w_u8(state, 66);
        rbs_types_function_forwarding_param_t *node = (rbs_types_function_forwarding_param_t *) instance;
        w_loc_range(state, node->base.location);
        return;
    }
    case RBS_TYPES_FUNCTION_PARAM: {
        w_u8(state, 67);
        rbs_types_function_param_t *node = (rbs_types_function_param_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->name_range);
        serialize_node(state, (rbs_node_t *) node->type);
        serialize_node(state, (rbs_node_t *) node->name);
        return;
    }
    case RBS_TYPES_INTERFACE: {
        w_u8(state, 68);
        rbs_types_interface_t *node = (rbs_types_interface_t *) instance;
        w_loc_range(state, node->base.location);
        w_loc_range(state, node->name_range);
        w_loc_range(state, node->args_range);
        serialize_node(state, (rbs_node_t *) node->name);
        w_node_list(state, node->args);
        return;
    }
    case RBS_TYPES_INTERSECTION: {
        w_u8(state, 69);
        rbs_types_intersection_t *node = (rbs_types_intersection_t *) instance;
        w_loc_range(state, node->base.location);
        w_node_list(state, node->types);
        return;
    }
    case RBS_TYPES_LITERAL: {
        w_u8(state, 70);
        rbs_types_literal_t *node = (rbs_types_literal_t *) instance;
        w_loc_range(state, node->base.location);
        serialize_node(state, (rbs_node_t *) node->literal);
        return;
    }
    case RBS_TYPES_OPTIONAL: {
        w_u8(state, 71);
        rbs_types_optional_t *node = (rbs_types_optional_t *) instance;
        w_loc_range(state, node->base.location);
        serialize_node(state, (rbs_node_t *) node->type);
        return;
    }
    case RBS_TYPES_PROC: {
        w_u8(state, 72);
        rbs_types_proc_t *node = (rbs_types_proc_t *) instance;
        w_loc_range(state, node->base.location);
        serialize_node(state, (rbs_node_t *) node->type);
        serialize_node(state, (rbs_node_t *) node->block);
        serialize_node(state, (rbs_node_t *) node->self_type);
        return;
    }
    case RBS_TYPES_RECORD: {
        w_u8(state, 73);
        rbs_types_record_t *node = (rbs_types_record_t *) instance;
        w_loc_range(state, node->base.location);
        w_hash(state, node->all_fields);
        return;
    }
    case RBS_TYPES_RECORD_FIELD_TYPE: {
        w_u8(state, 74);
        rbs_types_record_field_type_t *node = (rbs_types_record_field_type_t *) instance;
        serialize_node(state, node->type);
        w_u8(state, node->required ? 1 : 0);
        return;
    }
    case RBS_TYPES_TUPLE: {
        w_u8(state, 75);
        rbs_types_tuple_t *node = (rbs_types_tuple_t *) instance;
        w_loc_range(state, node->base.location);
        w_node_list(state, node->types);
        return;
    }
    case RBS_TYPES_UNION: {
        w_u8(state, 76);
        rbs_types_union_t *node = (rbs_types_union_t *) instance;
        w_loc_range(state, node->base.location);
        w_node_list(state, node->types);
        return;
    }
    case RBS_TYPES_UNTYPED_FUNCTION: {
        w_u8(state, 77);
        rbs_types_untyped_function_t *node = (rbs_types_untyped_function_t *) instance;
        serialize_node(state, (rbs_node_t *) node->return_type);
        return;
    }
    case RBS_TYPES_VARIABLE: {
        w_u8(state, 78);
        rbs_types_variable_t *node = (rbs_types_variable_t *) instance;
        w_loc_range(state, node->base.location);
        serialize_node(state, (rbs_node_t *) node->name);
        return;
    }
    case RBS_AST_SYMBOL: {
        w_u8(state, RBS_SERIALIZE_TAG_SYMBOL);
        w_constant(state, ((rbs_ast_symbol_t *) instance)->constant_id);
        return;
    }
    }

    RBS_ASSERT(false, "rbs_serialize_node: unknown node type: %d", instance->type);
}

rbs_string_t rbs_serialize_node(rbs_allocator_t *allocator, rbs_constant_pool_t *constant_pool, rbs_node_t *node) {
    rbs_serialize_state state = {
        .allocator = allocator,
        .constant_pool = constant_pool,
    };
    rbs_buffer_init(allocator, &state.buffer);

    serialize_node(&state, node);

    return rbs_buffer_to_string(&state.buffer);
}

rbs_string_t rbs_serialize_node_list(rbs_allocator_t *allocator, rbs_constant_pool_t *constant_pool, rbs_node_list_t *list) {
    rbs_serialize_state state = {
        .allocator = allocator,
        .constant_pool = constant_pool,
    };
    rbs_buffer_init(allocator, &state.buffer);

    w_node_list(&state, list);

    return rbs_buffer_to_string(&state.buffer);
}
