MODE: INLINE

static inline Sv get_send_message_params (Parser::MessageBuilder& builder, SV** args, I32 items) {
    Sv payload_sv;
    for (I32 i = 0; i < items - 1; i += 2) {
        auto name = xs::in<string_view>(args[i]);
        if (!name.length()) continue;
        auto val = args[i+1];
        switch (name[0]) {
            case 'd': if (name == "deflate" && sv_defined(val)) builder.deflate(SvTRUE(val)); break;
            case 'o': if (name == "opcode")  builder.opcode((Opcode)SvIV(val)); break;
            case 'p': if (name == "payload") payload_sv = val; break;
        }
    }
    return payload_sv;
}

MODULE = Protocol::WebSocket::Fast                PACKAGE = Protocol::WebSocket::Fast::Parser
PROTOTYPES: DISABLE

void Parser::configure (Parser::Config config)

size_t Parser::max_frame_size ()

size_t Parser::max_message_size ()

size_t Parser::max_handshake_size ()

Scalar Parser::deflate_config () {
    auto deflate_cfg = THIS->deflate_config();
    if (deflate_cfg) {
        RETVAL = xs::out(deflate_cfg.value());
    }
    else XSRETURN_UNDEF;
}

Scalar Parser::effective_deflate_config () {
    auto deflate_cfg = THIS->effective_deflate_config();
    if (deflate_cfg) {
        RETVAL = xs::out(deflate_cfg.value());
    }
    else XSRETURN_UNDEF;
}

bool Parser::established ()

bool Parser::recv_closed ()

bool Parser::send_closed ()

bool Parser::is_deflate_active ()

void Parser::get_frames (string buf = string()) {
    auto frames = buf ? THIS->get_frames(buf) : THIS->get_frames();
    if (GIMME_V == G_ARRAY) for (auto frame : frames) mXPUSHs(xs::out(frame).detach());
    else {
        if (frames.begin() == frames.end()) XSRETURN_UNDEF;
        auto itsv = xs::out(new XSFrameIterator(frames.begin()));
        mPUSHs(itsv.detach());
    }
}

void Parser::get_messages (string buf = string()) {
    auto messages = buf ? THIS->get_messages(buf) : THIS->get_messages();
    if (GIMME_V == G_ARRAY) for (auto message : messages) mXPUSHs(xs::out(message).detach());
    else {
        if (messages.begin() == messages.end()) XSRETURN_UNDEF;
        auto itsv = xs::out(new XSMessageIterator(messages.begin()));
        mPUSHs(itsv.detach());
    }
}

XSFrameSender* Parser::start_message (...) {
    Opcode opcode = Opcode::BINARY;
    auto deflate = DeflateFlag::NO;
    
    for (I32 i = 1; i < items - 1; i += 2) {
        auto name = xs::in<string_view>(ST(i));
        if (!name.length()) continue;
        auto val = ST(i+1);
        switch (name[0]) {
            case 'd': if (name == "deflate") deflate = SvTRUE(val) ? DeflateFlag::YES : DeflateFlag::NO; break;
            case 'o': if (name == "opcode")  opcode  = (Opcode)SvIV(val); break;
        }
    }
    
    RETVAL = new XSFrameSender(THIS->start_message(opcode, deflate));
}

string Parser::send_control (int opcode, string_view payload = {}) {
    RETVAL = THIS->send_control((Opcode)opcode, payload);
}

string Parser::send_ping (string_view payload = {}) {
    RETVAL = THIS->send_ping(payload);
}

string Parser::send_pong (string_view payload = {}) {
    RETVAL = THIS->send_pong(payload);
}

string Parser::send_close (SV* code = NULL, string_view message = string()) {
    RETVAL = code ? THIS->send_close((uint16_t)SvUV(code), message) :
                    THIS->send_close();
}

string Parser::send_message (...) {
    auto builder = THIS->message();
    Sv payload_sv = get_send_message_params(builder, &ST(1), items-1);
    
    if (payload_sv.is_array_ref()) {
        auto list = xs::in<std::vector<string_view>>(payload_sv);
        RETVAL = builder.send(list.begin(), list.end());
    }
    else {
        RETVAL = builder.send(xs::in<string_view>(payload_sv));
    }
}

Simple Parser::send_message_multiframe (...) {
    auto builder = THIS->message();
    Sv payload_sv = get_send_message_params(builder, &ST(1), items-1);
    auto payloads = xs::in<std::vector<string_view>>(payload_sv);
    auto range = builder.send_multiframe(payloads.begin(), payloads.end());
    RETVAL = strings_to_sv(range);
}

void Parser::reset ()

uint16_t Parser::suggested_close_code ()

void Parser::no_deflate ()