<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    <p>Hi! Thank you for review and fixes! I squashed you fixes and done<br>
      some changes:<br>
      - vstream_encode_port() now uses port_dump_msgpack() instead of<br>
        port_dump_msgpack_16()<br>
      - vstream now contains only inheritance_padding and vtab.<br>
      <br>
      New patch and some answers below.<br>
      <br>
    </p>
    <div class="moz-cite-prefix">On 11/23/18 12:49 AM, Vladislav
      Shpilevoy wrote:<br>
    </div>
    <blockquote type="cite"
      cite="mid:bca652ee-8489-f444-7a25-ccdb240c0afd@tarantool.org">Thanks
      for the fixes! See my 4 comments below, fix <br>
      at the end of the email and on the branch. <br>
      <br>
      On 22/11/2018 22:11, <a class="moz-txt-link-abbreviated"
        href="mailto:imeevma@tarantool.org">imeevma@tarantool.org</a>
      wrote: <br>
      <blockquote type="cite">If we want to use functions from execute.h
        not only in IPROTO we <br>
        should create special interface. This interface will allow us to
        <br>
        create different implementations for mpstream and lua_State and
        <br>
        use functions from execute.c without changing them. This patch <br>
        creates such interface and its implementation for mpstream and <br>
        replaces mpstream functions in execute.c by methods of this <br>
        interface. <br>
        <br>
        Needed for #3505 <br>
        --- <br>
          src/box/execute.c |  69 ++++++++++++----------- <br>
          src/box/execute.h |   6 +- <br>
          src/box/iproto.cc |  11 ++-- <br>
          src/box/vstream.h | 164
        ++++++++++++++++++++++++++++++++++++++++++++++++++++++ <br>
          src/mpstream.c    |  78 ++++++++++++++++++++++++++ <br>
          5 files changed, 291 insertions(+), 37 deletions(-) <br>
          create mode 100644 src/box/vstream.h <br>
        <br>
        diff --git a/src/box/execute.h b/src/box/execute.h <br>
        index 940f3a3..5a11a8a 100644 <br>
        --- a/src/box/execute.h <br>
        +++ b/src/box/execute.h <br>
        @@ -75,6 +75,8 @@ struct sql_response { <br>
              struct port port; <br>
              /** Prepared SQL statement with metadata. */ <br>
              void *prep_stmt; <br>
        +    /** Result should be flatten if true. */ <br>
        +    bool is_flatten; <br>
      </blockquote>
      <br>
      1. What does it mean 'result should be flatten'? Are all <br>
      tuples merged into a single flattened one? Or are all metafields <br>
      merged into a single array? Please, be more specific. It is far <br>
      from obvious now what is it 'flattened result'. <br>
      <br>
      Also, I guess, 'flatten' is a verb, so you can not say 'is
      flatten'. <br>
      Only 'is flattened'. <br>
    </blockquote>
    Squashed.<br>
    <blockquote type="cite"
      cite="mid:bca652ee-8489-f444-7a25-ccdb240c0afd@tarantool.org"> <br>
      2. I do not see where do you initialize this field for <br>
      iproto. So it is now initialized with stack garbage. <br>
      <br>
      (I've fixed all these things since we hurry.) <br>
    </blockquote>
    Squashed.
    <blockquote type="cite"
      cite="mid:bca652ee-8489-f444-7a25-ccdb240c0afd@tarantool.org"> <br>
      <blockquote type="cite">  }; <br>
            /** <br>
        diff --git a/src/box/vstream.h b/src/box/vstream.h <br>
        new file mode 100644 <br>
        index 0000000..a8dcfc2 <br>
        --- /dev/null <br>
        +++ b/src/box/vstream.h <br>
        @@ -0,0 +1,164 @@ <br>
        +#ifndef TARANTOOL_VSTREAM_H_INCLUDED <br>
        +#define TARANTOOL_VSTREAM_H_INCLUDED <br>
        +/* <br>
        + * Copyright 2010-2018, Tarantool AUTHORS, please see AUTHORS
        file. <br>
        + * <br>
        + * Redistribution and use in source and binary forms, with or <br>
        + * without modification, are permitted provided that the
        following <br>
        + * conditions are met: <br>
        + * <br>
        + * 1. Redistributions of source code must retain the above <br>
        + *    copyright notice, this list of conditions and the <br>
        + *    following disclaimer. <br>
        + * <br>
        + * 2. Redistributions in binary form must reproduce the above <br>
        + *    copyright notice, this list of conditions and the
        following <br>
        + *    disclaimer in the documentation and/or other materials <br>
        + *    provided with the distribution. <br>
        + * <br>
        + * THIS SOFTWARE IS PROVIDED BY AUTHORS ``AS IS'' AND <br>
        + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
        LIMITED <br>
        + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
        FOR <br>
        + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <br>
        + * AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, <br>
        + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL <br>
        + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF <br>
        + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
        OR <br>
        + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF <br>
        + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT <br>
        + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
        OF <br>
        + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
        OF <br>
        + * SUCH DAMAGE. <br>
        + */ <br>
        + <br>
        +#include "diag.h" <br>
        +#include "mpstream.h" <br>
      </blockquote>
      <br>
      3. vstream should not depend on mpstream, but vice versa. <br>
      Please, look at how struct port is done. It uses padding <br>
      into which its descendants can lay anything. <br>
    </blockquote>
    Squashed. Also removed "struct lua_State *" from vstream.<br>
    <blockquote type="cite"
      cite="mid:bca652ee-8489-f444-7a25-ccdb240c0afd@tarantool.org"> <br>
      <blockquote type="cite">+ <br>
        +#if defined(__cplusplus) <br>
        +extern "C" { <br>
        +#endif /* defined(__cplusplus) */ <br>
        + <br>
        +struct vstream; <br>
        +struct lua_State; <br>
        +struct port; <br>
        + <br>
        diff --git a/src/mpstream.c b/src/mpstream.c <br>
        index e4f7950..f9943e4 100644 <br>
        --- a/src/mpstream.c <br>
        +++ b/src/mpstream.c <br>
        @@ -175,3 +180,76 @@ mpstream_encode_bool(struct mpstream
        *stream, bool val) <br>
              char *pos = mp_encode_bool(data, val); <br>
              mpstream_advance(stream, pos - data); <br>
          } <br>
        + <br>
        +typedef void (*encode_array_f)(struct vstream *stream, uint32_t
        size); <br>
        +typedef void (*encode_map_f)(struct vstream *stream, uint32_t
        size); <br>
        +typedef void (*encode_uint_f)(struct vstream *stream, uint64_t
        num); <br>
        +typedef void (*encode_int_f)(struct vstream *stream, int64_t
        num); <br>
        +typedef void (*encode_float_f)(struct vstream *stream, float
        num); <br>
        +typedef void (*encode_double_f)(struct vstream *stream, double
        num); <br>
        +typedef void (*encode_strn_f)(struct vstream *stream, const
        char *str, <br>
        +                  uint32_t len); <br>
        +typedef void (*encode_nil_f)(struct vstream *stream); <br>
        +typedef void (*encode_bool_f)(struct vstream *stream, bool
        val); <br>
        + <br>
      </blockquote>
      <br>
      4. I think, it should be part of vstream.h. And struct vstream
      members should be <br>
      defined with these types. <br>
    </blockquote>
    Squashed.
    <p><br>
    </p>
    <p><b>New version:</b></p>
    <p>commit 795ccb629260269c8ffffb52d5e426e35ed0a088<br>
      Author: Mergen Imeev <a class="moz-txt-link-rfc2396E"
        href="mailto:imeevma@gmail.com"><imeevma@gmail.com></a><br>
      Date:   Sat Nov 10 11:18:32 2018 +0300<br>
      <br>
          sql: create interface vstream<br>
          <br>
          If we want to use functions from execute.h not only in IPROTO
      we<br>
          should create special interface. This interface will allow us
      to<br>
          create different implementations for mpstream and lua_State
      and<br>
          use functions from execute.c without changing them. This patch<br>
          creates such interface and its implementation for mpstream and<br>
          replaces mpstream functions in execute.c by methods of this<br>
          interface.<br>
          <br>
          Needed for #3505<br>
      <br>
      diff --git a/src/box/execute.c b/src/box/execute.c<br>
      index 9ba9e66..0fee5c1 100644<br>
      --- a/src/box/execute.c<br>
      +++ b/src/box/execute.c<br>
      @@ -42,7 +42,7 @@<br>
       #include "port.h"<br>
       #include "tuple.h"<br>
       #include "sql/vdbe.h"<br>
      -#include "mpstream.h"<br>
      +#include "vstream.h"<br>
       <br>
       const char *sql_type_strs[] = {<br>
           NULL,<br>
      @@ -530,12 +530,12 @@ sql_bind(const struct sql_request *request,
      struct sqlite3_stmt *stmt)<br>
        * @retval -1 Client or memory error.<br>
        */<br>
       static inline int<br>
      -sql_get_description(struct sqlite3_stmt *stmt, struct mpstream
      *stream,<br>
      +sql_get_description(struct sqlite3_stmt *stmt, struct vstream
      *stream,<br>
                   int column_count)<br>
       {<br>
           assert(column_count > 0);<br>
      -    mpstream_encode_uint(stream, IPROTO_METADATA);<br>
      -    mpstream_encode_array(stream, column_count);<br>
      +    vstream_encode_enum(stream, IPROTO_METADATA, "metadata");<br>
      +    vstream_encode_array(stream, column_count);<br>
           for (int i = 0; i < column_count; ++i) {<br>
               const char *name = sqlite3_column_name(stmt, i);<br>
               const char *type = sqlite3_column_datatype(stmt, i);<br>
      @@ -547,12 +547,19 @@ sql_get_description(struct sqlite3_stmt
      *stmt, struct mpstream *stream,<br>
               assert(name != NULL);<br>
               if (type == NULL)<br>
                   type = "UNKNOWN";<br>
      -        mpstream_encode_map(stream, 2);<br>
      -        mpstream_encode_uint(stream, IPROTO_FIELD_NAME);<br>
      -        mpstream_encode_str(stream, name);<br>
      -        mpstream_encode_uint(stream, IPROTO_FIELD_TYPE);<br>
      -        mpstream_encode_str(stream, type);<br>
      +        vstream_encode_map(stream, 2);<br>
      +<br>
      +        vstream_encode_enum(stream, IPROTO_FIELD_NAME, "name");<br>
      +        vstream_encode_str(stream, name);<br>
      +        vstream_encode_map_commit(stream);<br>
      +<br>
      +        vstream_encode_enum(stream, IPROTO_FIELD_TYPE, "type");<br>
      +        vstream_encode_str(stream, type);<br>
      +        vstream_encode_map_commit(stream);<br>
      +<br>
      +        vstream_encode_array_commit(stream, i);<br>
           }<br>
      +    vstream_encode_map_commit(stream);<br>
           return 0;<br>
       }<br>
       <br>
      @@ -611,7 +618,7 @@ sql_prepare_and_execute(const struct
      sql_request *request,<br>
       <br>
       int<br>
       sql_response_dump(struct sql_response *response, int *keys,<br>
      -          struct mpstream *stream)<br>
      +          struct vstream *stream)<br>
       {<br>
           sqlite3 *db = sql_get();<br>
           struct sqlite3_stmt *stmt = (struct sqlite3_stmt *)
      response->prep_stmt;<br>
      @@ -623,42 +630,48 @@ err:<br>
                   goto finish;<br>
               }<br>
               *keys = 2;<br>
      -        mpstream_encode_uint(stream, IPROTO_DATA);<br>
      -        mpstream_flush(stream);<br>
      -        if (port_dump_msgpack(&response->port,
      stream->ctx) < 0) {<br>
      +        vstream_encode_enum(stream, IPROTO_DATA, "rows");<br>
      +        if (vstream_encode_port(stream, &response->port)
      < 0) {<br>
                   /* Failed port dump destroyes the port. */<br>
                   goto err;<br>
               }<br>
      -        mpstream_reset(stream);<br>
      +        vstream_encode_map_commit(stream);<br>
           } else {<br>
               *keys = 1;<br>
               struct stailq *autoinc_id_list =<br>
                   vdbe_autoinc_id_list((struct Vdbe *)stmt);<br>
               uint32_t map_size = stailq_empty(autoinc_id_list) ? 1 :
      2;<br>
      -        mpstream_encode_uint(stream, IPROTO_SQL_INFO);<br>
      -        mpstream_encode_map(stream, map_size);<br>
               uint64_t id_count = 0;<br>
               if (!stailq_empty(autoinc_id_list)) {<br>
                   struct autoinc_id_entry *id_entry;<br>
                   stailq_foreach_entry(id_entry, autoinc_id_list, link)<br>
                       id_count++;<br>
               }<br>
      -<br>
      -        mpstream_encode_uint(stream, SQL_INFO_ROW_COUNT);<br>
      -        mpstream_encode_uint(stream, db->nChange);<br>
      +        if (!response->is_info_flattened) {<br>
      +            vstream_encode_enum(stream, IPROTO_SQL_INFO, "info");<br>
      +            vstream_encode_map(stream, map_size);<br>
      +        }<br>
      +        vstream_encode_enum(stream, SQL_INFO_ROW_COUNT,
      "rowcount");<br>
      +        vstream_encode_uint(stream, db->nChange);<br>
      +        vstream_encode_map_commit(stream);<br>
               if (!stailq_empty(autoinc_id_list)) {<br>
      -            mpstream_encode_uint(stream,<br>
      -                         SQL_INFO_AUTOINCREMENT_IDS);<br>
      -            mpstream_encode_array(stream, id_count);<br>
      +            vstream_encode_enum(stream,
      SQL_INFO_AUTOINCREMENT_IDS,<br>
      +                        "autoincrement_ids");<br>
      +            vstream_encode_array(stream, id_count);<br>
                   struct autoinc_id_entry *id_entry;<br>
      +            int i = 0;<br>
                   stailq_foreach_entry(id_entry, autoinc_id_list, link)
      {<br>
                       int64_t value = id_entry->id;<br>
                       if (id_entry->id >= 0)<br>
      -                    mpstream_encode_uint(stream, value);<br>
      +                    vstream_encode_uint(stream, value);<br>
                       else<br>
      -                    mpstream_encode_int(stream, value);<br>
      +                    vstream_encode_int(stream, value);<br>
      +                vstream_encode_array_commit(stream, i++);<br>
                   }<br>
      +            vstream_encode_map_commit(stream);<br>
               }<br>
      +        if (!response->is_info_flattened)<br>
      +            vstream_encode_map_commit(stream);<br>
           }<br>
       finish:<br>
           port_destroy(&response->port);<br>
      diff --git a/src/box/execute.h b/src/box/execute.h<br>
      index 65ac81c..56b7339 100644<br>
      --- a/src/box/execute.h<br>
      +++ b/src/box/execute.h<br>
      @@ -51,7 +51,7 @@ extern const char *sql_info_key_strs[];<br>
       struct region;<br>
       struct sql_bind;<br>
       struct xrow_header;<br>
      -struct mpstream;<br>
      +struct vstream;<br>
       <br>
       /** EXECUTE request. */<br>
       struct sql_request {<br>
      @@ -74,6 +74,20 @@ struct sql_response {<br>
           struct port port;<br>
           /** Prepared SQL statement with metadata. */<br>
           void *prep_stmt;<br>
      +    /**<br>
      +     * SQL response can be dumped into msgpack to be sent via<br>
      +     * iproto or onto Lua stack to be returned into an<br>
      +     * application. In the first case response body has<br>
      +     * explicit field IPROTO_SQL_INFO: {rowcount = ...,<br>
      +     * autoids = ...}. But in case of Lua this field is<br>
      +     * flattened. A result never has 'info' field, it has<br>
      +     * inlined 'rowcount' and 'autoids'. In iproto<br>
      +     * IPROTO_SQL_INFO field is sent mostly to explicitly<br>
      +     * distinguish two response types: DML/DDL vs DQL,<br>
      +     * IPROTO_SQL_INFO vs IPROTO_METADATA. So this flag is set<br>
      +     * by Lua and allows to flatten SQL_INFO fields.<br>
      +     */<br>
      +    bool is_info_flattened;<br>
       };<br>
       <br>
       /**<br>
      @@ -112,7 +126,7 @@ struct sql_response {<br>
        */<br>
       int<br>
       sql_response_dump(struct sql_response *response, int *keys,<br>
      -          struct mpstream *stream);<br>
      +          struct vstream *stream);<br>
       <br>
       /**<br>
        * Parse the EXECUTE request.<br>
      diff --git a/src/box/iproto.cc b/src/box/iproto.cc<br>
      index b110900..1c4c651 100644<br>
      --- a/src/box/iproto.cc<br>
      +++ b/src/box/iproto.cc<br>
      @@ -62,6 +62,7 @@<br>
       #include "execute.h"<br>
       #include "errinj.h"<br>
       #include "mpstream.h"<br>
      +#include "vstream.h"<br>
       <br>
       enum {<br>
           IPROTO_SALT_SIZE = 32,<br>
      @@ -1587,6 +1588,7 @@ tx_process_sql(struct cmsg *m)<br>
           struct iproto_msg *msg = tx_accept_msg(m);<br>
           struct obuf *out;<br>
           struct sql_response response;<br>
      +    memset(&response, 0, sizeof(response));<br>
           bool is_error = false;<br>
       <br>
           tx_fiber_init(msg->connection->session,
      msg->header.sync);<br>
      @@ -1607,16 +1609,18 @@ tx_process_sql(struct cmsg *m)<br>
           /* Prepare memory for the iproto header. */<br>
           if (iproto_prepare_header(out, &header_svp,
      IPROTO_SQL_HEADER_LEN) != 0)<br>
               goto error;<br>
      -    struct mpstream stream;<br>
      -    mpstream_init(&stream, out, obuf_reserve_cb,
      obuf_alloc_cb,<br>
      -              set_encode_error, &is_error);<br>
      +<br>
      +    struct vstream stream;<br>
      +    mpstream_init((struct mpstream *)&stream, out,
      obuf_reserve_cb,<br>
      +              obuf_alloc_cb, set_encode_error, &is_error);<br>
           if (is_error)<br>
               goto error;<br>
      +    mp_vstream_init_vtab(&stream);<br>
           if (sql_response_dump(&response, &keys, &stream)
      != 0 || is_error) {<br>
               obuf_rollback_to_svp(out, &header_svp);<br>
               goto error;<br>
           }<br>
      -    mpstream_flush(&stream);<br>
      +    mpstream_flush((struct mpstream *)&stream);<br>
           iproto_reply_sql(out, &header_svp, response.sync,
      schema_version, keys);<br>
           iproto_wpos_create(&msg->wpos, out);<br>
           return;<br>
      diff --git a/src/box/vstream.h b/src/box/vstream.h<br>
      new file mode 100644<br>
      index 0000000..01a5212<br>
      --- /dev/null<br>
      +++ b/src/box/vstream.h<br>
      @@ -0,0 +1,171 @@<br>
      +#ifndef TARANTOOL_VSTREAM_H_INCLUDED<br>
      +#define TARANTOOL_VSTREAM_H_INCLUDED<br>
      +/*<br>
      + * Copyright 2010-2018, Tarantool AUTHORS, please see AUTHORS
      file.<br>
      + *<br>
      + * Redistribution and use in source and binary forms, with or<br>
      + * without modification, are permitted provided that the
      following<br>
      + * conditions are met:<br>
      + *<br>
      + * 1. Redistributions of source code must retain the above<br>
      + *    copyright notice, this list of conditions and the<br>
      + *    following disclaimer.<br>
      + *<br>
      + * 2. Redistributions in binary form must reproduce the above<br>
      + *    copyright notice, this list of conditions and the following<br>
      + *    disclaimer in the documentation and/or other materials<br>
      + *    provided with the distribution.<br>
      + *<br>
      + * THIS SOFTWARE IS PROVIDED BY AUTHORS ``AS IS'' AND<br>
      + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED<br>
      + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR<br>
      + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL<br>
      + * AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,<br>
      + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL<br>
      + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF<br>
      + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
      OR<br>
      + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF<br>
      + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT<br>
      + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF<br>
      + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
      OF<br>
      + * SUCH DAMAGE.<br>
      + */<br>
      +#if defined(__cplusplus)<br>
      +extern "C" {<br>
      +#endif /* defined(__cplusplus) */<br>
      +<br>
      +struct vstream;<br>
      +struct lua_State;<br>
      +struct port;<br>
      +<br>
      +typedef void (*encode_array_f)(struct vstream *stream, uint32_t
      size);<br>
      +typedef void (*encode_map_f)(struct vstream *stream, uint32_t
      size);<br>
      +typedef void (*encode_uint_f)(struct vstream *stream, uint64_t
      num);<br>
      +typedef void (*encode_int_f)(struct vstream *stream, int64_t
      num);<br>
      +typedef void (*encode_float_f)(struct vstream *stream, float
      num);<br>
      +typedef void (*encode_double_f)(struct vstream *stream, double
      num);<br>
      +typedef void (*encode_strn_f)(struct vstream *stream, const char
      *str,<br>
      +                  uint32_t len);<br>
      +typedef void (*encode_nil_f)(struct vstream *stream);<br>
      +typedef void (*encode_bool_f)(struct vstream *stream, bool val);<br>
      +typedef void (*encode_enum_f)(struct vstream *stream, int64_t
      num,<br>
      +                  const char *str);<br>
      +typedef int (*encode_port_f)(struct vstream *stream, struct port
      *port);<br>
      +typedef void (*encode_array_commit_f)(struct vstream *stream,
      uint32_t id);<br>
      +typedef void (*encode_map_commit_f)(struct vstream *stream);<br>
      +<br>
      +struct vstream_vtab {<br>
      +    encode_array_f encode_array;<br>
      +    encode_map_f encode_map;<br>
      +    encode_uint_f encode_uint;<br>
      +    encode_int_f encode_int;<br>
      +    encode_float_f encode_float;<br>
      +    encode_double_f encode_double;<br>
      +    encode_strn_f encode_strn;<br>
      +    encode_nil_f encode_nil;<br>
      +    encode_bool_f encode_bool;<br>
      +    encode_enum_f encode_enum;<br>
      +    encode_port_f encode_port;<br>
      +    encode_array_commit_f encode_array_commit;<br>
      +    encode_map_commit_f encode_map_commit;<br>
      +};<br>
      +<br>
      +struct vstream {<br>
      +    /** Here struct mpstream lives under the hood. */<br>
      +    char inheritance_padding[64];<br>
      +    /** Virtual function table. */<br>
      +    const struct vstream_vtab *vtab;<br>
      +};<br>
      +<br>
      +void<br>
      +mp_vstream_init_vtab(struct vstream *vstream);<br>
      +<br>
      +static inline void<br>
      +vstream_encode_array(struct vstream *stream, uint32_t size)<br>
      +{<br>
      +    return stream->vtab->encode_array(stream, size);<br>
      +}<br>
      +<br>
      +static inline void<br>
      +vstream_encode_map(struct vstream *stream, uint32_t size)<br>
      +{<br>
      +    return stream->vtab->encode_map(stream, size);<br>
      +}<br>
      +<br>
      +static inline void<br>
      +vstream_encode_uint(struct vstream *stream, uint64_t num)<br>
      +{<br>
      +    return stream->vtab->encode_uint(stream, num);<br>
      +}<br>
      +<br>
      +static inline void<br>
      +vstream_encode_int(struct vstream *stream, int64_t num)<br>
      +{<br>
      +    return stream->vtab->encode_int(stream, num);<br>
      +}<br>
      +<br>
      +static inline void<br>
      +vstream_encode_float(struct vstream *stream, float num)<br>
      +{<br>
      +    return stream->vtab->encode_float(stream, num);<br>
      +}<br>
      +<br>
      +static inline void<br>
      +vstream_encode_double(struct vstream *stream, double num)<br>
      +{<br>
      +    return stream->vtab->encode_double(stream, num);<br>
      +}<br>
      +<br>
      +static inline void<br>
      +vstream_encode_strn(struct vstream *stream, const char *str,
      uint32_t len)<br>
      +{<br>
      +    return stream->vtab->encode_strn(stream, str, len);<br>
      +}<br>
      +<br>
      +static inline void<br>
      +vstream_encode_str(struct vstream *stream, const char *str)<br>
      +{<br>
      +    return stream->vtab->encode_strn(stream, str,
      strlen(str));<br>
      +}<br>
      +<br>
      +static inline void<br>
      +vstream_encode_nil(struct vstream *stream)<br>
      +{<br>
      +    return stream->vtab->encode_nil(stream);<br>
      +}<br>
      +<br>
      +static inline void<br>
      +vstream_encode_bool(struct vstream *stream, bool val)<br>
      +{<br>
      +    return stream->vtab->encode_bool(stream, val);<br>
      +}<br>
      +<br>
      +static inline void<br>
      +vstream_encode_enum(struct vstream *stream, int64_t num, const
      char *str)<br>
      +{<br>
      +    return stream->vtab->encode_enum(stream, num, str);<br>
      +}<br>
      +<br>
      +static inline int<br>
      +vstream_encode_port(struct vstream *stream, struct port *port)<br>
      +{<br>
      +    return stream->vtab->encode_port(stream, port);<br>
      +}<br>
      +<br>
      +static inline void<br>
      +vstream_encode_map_commit(struct vstream *stream)<br>
      +{<br>
      +    return stream->vtab->encode_map_commit(stream);<br>
      +}<br>
      +<br>
      +static inline void<br>
      +vstream_encode_array_commit(struct vstream *stream, uint32_t id)<br>
      +{<br>
      +    return stream->vtab->encode_array_commit(stream, id);<br>
      +}<br>
      +<br>
      +#if defined(__cplusplus)<br>
      +} /* extern "C" */<br>
      +#endif /* defined(__cplusplus) */<br>
      +<br>
      +#endif /* TARANTOOL_VSTREAM_H_INCLUDED */<br>
      diff --git a/src/mpstream.c b/src/mpstream.c<br>
      index e4f7950..4091ead 100644<br>
      --- a/src/mpstream.c<br>
      +++ b/src/mpstream.c<br>
      @@ -33,6 +33,8 @@<br>
       #include <assert.h><br>
       #include <stdint.h><br>
       #include "msgpuck.h"<br>
      +#include "box/vstream.h"<br>
      +#include "box/port.h"<br>
       <br>
       void<br>
       mpstream_reserve_slow(struct mpstream *stream, size_t size)<br>
      @@ -175,3 +177,54 @@ mpstream_encode_bool(struct mpstream *stream,
      bool val)<br>
           char *pos = mp_encode_bool(data, val);<br>
           mpstream_advance(stream, pos - data);<br>
       }<br>
      +<br>
      +int<br>
      +mp_vstream_encode_port(struct vstream *stream, struct port *port)<br>
      +{<br>
      +    struct mpstream *mpstream = (struct mpstream *)stream;<br>
      +    mpstream_flush(mpstream);<br>
      +    if (port_dump_msgpack(port, mpstream->ctx) < 0) {<br>
      +        /* Failed port dump destroyes the port. */<br>
      +        return -1;<br>
      +    }<br>
      +    mpstream_reset(mpstream);<br>
      +    return 0;<br>
      +}<br>
      +<br>
      +void<br>
      +mp_vstream_encode_enum(struct vstream *stream, int64_t num, const
      char *str)<br>
      +{<br>
      +    (void)str;<br>
      +    if (num < 0)<br>
      +        mpstream_encode_int((struct mpstream *)stream, num);<br>
      +    else<br>
      +        mpstream_encode_uint((struct mpstream *)stream, num);<br>
      +}<br>
      +<br>
      +void<br>
      +mp_vstream_noop(struct vstream *stream, ...)<br>
      +{<br>
      +    (void) stream;<br>
      +}<br>
      +<br>
      +const struct vstream_vtab mp_vstream_vtab = {<br>
      +    /** encode_array = */ (encode_array_f)mpstream_encode_array,<br>
      +    /** encode_map = */ (encode_map_f)mpstream_encode_map,<br>
      +    /** encode_uint = */ (encode_uint_f)mpstream_encode_uint,<br>
      +    /** encode_int = */ (encode_int_f)mpstream_encode_int,<br>
      +    /** encode_float = */ (encode_float_f)mpstream_encode_float,<br>
      +    /** encode_double = */
      (encode_double_f)mpstream_encode_double,<br>
      +    /** encode_strn = */ (encode_strn_f)mpstream_encode_strn,<br>
      +    /** encode_nil = */ (encode_nil_f)mpstream_encode_nil,<br>
      +    /** encode_bool = */ (encode_bool_f)mpstream_encode_bool,<br>
      +    /** encode_enum = */ mp_vstream_encode_enum,<br>
      +    /** encode_port = */ mp_vstream_encode_port,<br>
      +    /** encode_array_commit = */
      (encode_array_commit_f)mp_vstream_noop,<br>
      +    /** encode_map_commit = */
      (encode_map_commit_f)mp_vstream_noop,<br>
      +};<br>
      +<br>
      +void<br>
      +mp_vstream_init_vtab(struct vstream *vstream)<br>
      +{<br>
      +    vstream->vtab = &mp_vstream_vtab;<br>
      +}<br>
      <br>
    </p>
  </body>
</html>