redis: rename _args_size/_size_left
There are two types of numerical parameter in redis protocol:
 - *[0-9]+ defined array size
 - $[0-9]+ defined string size

Currently, array size is stored to args_count, and string size is
stored to _arg_size / _size_left.
It's bit hard to understand since both uses same word "arg(s)", let's
rename string size variables to _bytes_count / _bytes_left.

/*
 * Copyright (C) 2019 pengjian.uestc @ gmail.com
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <memory>
#include <iostream>
#include <algorithm>
#include <functional>
#include "bytes.hh"
#include "redis/request.hh"
#include <seastar/core/ragel.hh>

using namespace seastar;
using namespace redis;
%%{

machine redis_resp_protocol;

access _fsm_;

action mark {
    g.mark_start(p);
}

action start_blob {
    g.mark_start(p);
    _bytes_left = _bytes_count;
}

action start_command {
    g.mark_start(p);
    _bytes_left = _bytes_count;
}

action advance_blob {
    auto len = std::min(static_cast<uint32_t>(pe - p), _bytes_left);
    _bytes_left -= len;
    p += len;
    if (_bytes_left == 0) {
      _req._args.push_back(str());
      p--;
      fret;
    }
    p--;
}

action advance_command {
    auto len = std::min(static_cast<uint32_t>(pe - p), _bytes_left);
    _bytes_left -= len;
    p += len;
    if (_bytes_left == 0) {
      _req._command = str();
      p--;
      fret;
    }
    p--;
}

crlf = '\r\n';
u32 = digit+ >{ _u32 = 0;}  ${ _u32 *= 10; _u32 += fc - '0';};
args_count = '*' u32 crlf ${_req._args_count = _u32 - 1;};
blob := any+ >start_blob $advance_blob;
command := any+ >start_command $advance_command;
arg = '$' u32 crlf ${ _bytes_count = _u32;};

main := (args_count (arg @{fcall command; } crlf) (arg @{fcall blob; } crlf)+) ${_req._state = request_state::ok;} >eof{_req._state = request_state::eof;};

prepush {
    prepush();
}

postpop {
    postpop();
}

}%%

class redis_protocol_parser : public ragel_parser_base<redis_protocol_parser> {
    %% write data nofinal noprefix;
public:
    redis::request _req;
    uint32_t _u32;
    uint32_t _bytes_count;
    uint32_t _bytes_left;
public:
    virtual void init() {
        init_base();
        _req._state = request_state::error;
        _req._args.clear();
        _req._args_count = 0;
        _bytes_left = 0;
        _bytes_count = 0;
        %% write init;
    }

    char* parse(char* p, char* pe, char* eof) {
        sstring_builder::guard g(_builder, p, pe);
        auto str = [this, &g, &p] {
            g.mark_end(p);
            auto s =  get_str();
            return to_bytes(s);
        };

        %% write exec;
        // does not reach to the tail of the message, continue reading
        if (_bytes_left || _req._args_count - _req._args.size()) {
            return nullptr;
        }

        if (_req._state != request_state::error) {
            return p;
        }
        if (p != pe) {
            p = pe;
            return p;
        }
        return nullptr;
    }

    bool eof() const {
        return _req._state == request_state::eof;
    }

    bool failed() const {
        return _req._state == request_state::error;
    }

    redis::request& get_request() {
        std::transform(_req._command.begin(), _req._command.end(), _req._command.begin(), ::tolower);
        return _req;
    }
};

/*
 * Copyright (C) 2019 pengjian.uestc @ gmail.com
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <memory>
#include <iostream>
#include <algorithm>
#include <functional>
#include "bytes.hh"
#include "redis/request.hh"
#include <seastar/core/ragel.hh>

using namespace seastar;
using namespace redis;
%%{

machine redis_resp_protocol;

access _fsm_;

action mark {
    g.mark_start(p);
}

action start_blob {
    g.mark_start(p);
    _size_left = _arg_size;
}

action start_command {
    g.mark_start(p);
    _size_left = _arg_size;
}

action advance_blob {
    auto len = std::min(static_cast<uint32_t>(pe - p), _size_left);
    _size_left -= len;
    p += len;
    if (_size_left == 0) {
      _req._args.push_back(str());
      p--;
      fret;
    }
    p--;
}

action advance_command {
    auto len = std::min(static_cast<uint32_t>(pe - p), _size_left);
    _size_left -= len;
    p += len;
    if (_size_left == 0) {
      _req._command = str();
      p--;
      fret;
    }
    p--;
}

crlf = '\r\n';
u32 = digit+ >{ _u32 = 0;}  ${ _u32 *= 10; _u32 += fc - '0';};
args_count = '*' u32 crlf ${_req._args_count = _u32 - 1;};
blob := any+ >start_blob $advance_blob;
command := any+ >start_command $advance_command;
arg = '$' u32 crlf ${ _arg_size = _u32;};

main := (args_count (arg @{fcall command; } crlf) (arg @{fcall blob; } crlf)+) ${_req._state = request_state::ok;} >eof{_req._state = request_state::eof;};

prepush {
    prepush();
}

postpop {
    postpop();
}

}%%

class redis_protocol_parser : public ragel_parser_base<redis_protocol_parser> {
    %% write data nofinal noprefix;
public:
    redis::request _req;
    uint32_t _u32;
    uint32_t _arg_size;
    uint32_t _size_left;
public:
    virtual void init() {
        init_base();
        _req._state = request_state::error;
        _req._args.clear();
        _req._args_count = 0;
        _size_left = 0;
        _arg_size = 0;
        %% write init;
    }

    char* parse(char* p, char* pe, char* eof) {
        sstring_builder::guard g(_builder, p, pe);
        auto str = [this, &g, &p] {
            g.mark_end(p);
            auto s =  get_str();
            return to_bytes(s);
        };

        %% write exec;
        // does not reach to the tail of the message, continue reading
        if (_size_left || _req._args_count - _req._args.size()) {
            return nullptr;
        }

        if (_req._state != request_state::error) {
            return p;
        }
        if (p != pe) {
            p = pe;
            return p;
        }
        return nullptr;
    }

    bool eof() const {
        return _req._state == request_state::eof;
    }

    bool failed() const {
        return _req._state == request_state::error;
    }

    redis::request& get_request() {
        std::transform(_req._command.begin(), _req._command.end(), _req._command.begin(), ::tolower);
        return _req;
    }
};