Tarantool development patches archive
 help / color / mirror / Atom feed
From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org>
To: tarantool-patches@freelists.org
Cc: vdavydov.dev@gmail.com
Subject: [PATCH v2 02/10] yaml: introduce yaml.encode_tagged
Date: Fri, 20 Apr 2018 16:24:27 +0300	[thread overview]
Message-ID: <7c30b9483a38bd36425d7e0c87b4d15e8893446e.1524228894.git.v.shpilevoy@tarantool.org> (raw)
In-Reply-To: <cover.1524228894.git.v.shpilevoy@tarantool.org>
In-Reply-To: <cover.1524228894.git.v.shpilevoy@tarantool.org>

Encode_tagged allows to define one global YAML tag for a
document. Tagged YAML documents are going to be used for
console text pushes to distinguish actual box.session.push() from
console.print(). The first will have tag !push, and the
second - !print.
---
 test/app-tap/yaml.test.lua    | 23 ++++++++++++++-
 third_party/lua-yaml/lyaml.cc | 69 +++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 88 insertions(+), 4 deletions(-)

diff --git a/test/app-tap/yaml.test.lua b/test/app-tap/yaml.test.lua
index def278570..b81402cc0 100755
--- a/test/app-tap/yaml.test.lua
+++ b/test/app-tap/yaml.test.lua
@@ -69,9 +69,29 @@ local function test_output(test, s)
         "--- |-\n  Tutorial -- Header\n  ====\n\n  Text\n...\n", "tutorial string");
 end
 
+local function test_tagged(test, s)
+    test:plan(7)
+    local must_be_err = 'Usage: encode_tagged({prefix = <string>, handle = <string>}, object)'
+    local prefix = 'tag:tarantool.io/push,2018'
+    local ok, err = pcall(s.encode_tagged)
+    test:is(err, must_be_err, "encode_tagged usage")
+    ok, err = pcall(s.encode_tagged, {}, 100)
+    test:is(err, must_be_err, "encode_tagged usage")
+    ok, err = pcall(s.encode_tagged, {handle = true, prefix = 100}, 200)
+    test:is(err, must_be_err, "encode_tagged usage")
+    local ret
+    ret, err = s.encode_tagged({handle = '!push', prefix = prefix}, 300)
+    test:is(ret, nil, 'non-usage and non-oom errors do not raise')
+    test:is(err, "tag handle must end with '!'", "encode_tagged usage")
+    ret = s.encode_tagged({handle = '!push!', prefix = prefix}, 300)
+    test:is(ret, "%TAG !push! "..prefix.."\n--- 300\n...\n", "encode_tagged usage")
+    ret = s.encode_tagged({handle = '!print!', prefix = prefix}, {a = 100, b = 200})
+    test:is(ret, "%TAG !print! tag:tarantool.io/push,2018\n---\na: 100\nb: 200\n...\n", 'encode_tagged usage')
+end
+
 tap.test("yaml", function(test)
     local serializer = require('yaml')
-    test:plan(10)
+    test:plan(11)
     test:test("unsigned", common.test_unsigned, serializer)
     test:test("signed", common.test_signed, serializer)
     test:test("double", common.test_double, serializer)
@@ -82,4 +102,5 @@ tap.test("yaml", function(test)
     test:test("ucdata", common.test_ucdata, serializer)
     test:test("compact", test_compact, serializer)
     test:test("output", test_output, serializer)
+    test:test("tagged", test_tagged, serializer)
 end)
diff --git a/third_party/lua-yaml/lyaml.cc b/third_party/lua-yaml/lyaml.cc
index 430f4be2c..8329f84e9 100644
--- a/third_party/lua-yaml/lyaml.cc
+++ b/third_party/lua-yaml/lyaml.cc
@@ -78,6 +78,8 @@ struct lua_yaml_dumper {
    unsigned int anchor_number;
    yaml_emitter_t emitter;
    char error;
+   yaml_tag_directive_t begin_tag;
+   yaml_tag_directive_t *end_tag;
 
    lua_State *outputL;
    luaL_Buffer yamlbuf;
@@ -571,7 +573,8 @@ static int dump_node(struct lua_yaml_dumper *dumper)
 static void dump_document(struct lua_yaml_dumper *dumper) {
    yaml_event_t ev;
 
-   if (!yaml_document_start_event_initialize(&ev, NULL, NULL, NULL, 0) ||
+   if (!yaml_document_start_event_initialize(&ev, NULL, &dumper->begin_tag,
+                                             dumper->end_tag, 0) ||
        !yaml_emitter_emit(&dumper->emitter, &ev))
       return;
 
@@ -618,13 +621,38 @@ static void find_references(struct lua_yaml_dumper *dumper) {
    }
 }
 
-static int l_dump(lua_State *L) {
+/**
+ * Encode a Lua object or objects into YAML documents onto Lua
+ * stack.
+ * @param L Lua stack to get arguments and push result.
+ * @param serializer Lua YAML serializer.
+ * @param tag_handle NULL, or a global tag handle. Handle becomes
+ *        a synonym for prefix.
+ * @param tag_prefix NULL, or a global tag prefix, to which @a
+ *        handle is expanded.
+ * @retval nil, error Error.
+ * @retval not nil Lua string with dumped object.
+ */
+static int
+lua_yaml_encode_impl(lua_State *L, struct luaL_serializer *serializer,
+                     const char *tag_handle, const char *tag_prefix)
+{
    struct lua_yaml_dumper dumper;
    int i, argcount = lua_gettop(L);
    yaml_event_t ev;
 
    dumper.L = L;
-   dumper.cfg = luaL_checkserializer(L);
+   dumper.begin_tag.handle = (yaml_char_t *) tag_handle;
+   dumper.begin_tag.prefix = (yaml_char_t *) tag_prefix;
+   /*
+    * If a tag is specified, then tag list is not empty and
+    * consists of a single tag.
+    */
+   if (tag_handle != NULL && tag_prefix != NULL)
+      dumper.end_tag = &dumper.begin_tag + 1;
+   else
+      dumper.end_tag = &dumper.begin_tag;
+   dumper.cfg = serializer;
    dumper.error = 0;
    /* create thread to use for YAML buffer */
    dumper.outputL = lua_newthread(L);
@@ -684,11 +712,46 @@ error:
    }
 }
 
+static int l_dump(lua_State *L) {
+   return lua_yaml_encode_impl(L, luaL_checkserializer(L), NULL, NULL);
+}
+
+/**
+ * Dump a Lua object into YAML string with a global TAG specified.
+ * @param options First argument on a stack, consists of two
+ *        options: tag prefix and tag handle.
+ * @param object Lua object to dump under the global tag.
+ * @retval Lua string with dumped object.
+ */
+static int l_dump_tagged(lua_State *L)
+{
+   struct luaL_serializer *serializer = luaL_checkserializer(L);
+   int argcount = lua_gettop(L);
+   if (argcount != 2 || !lua_istable(L, 1)) {
+usage_error:
+      return luaL_error(L, "Usage: encode_tagged({prefix = <string>, "\
+                           "handle = <string>}, object)");
+   }
+   lua_getfield(L, 1, "prefix");
+   if (! lua_isstring(L, -1))
+      goto usage_error;
+   const char *prefix = lua_tostring(L, -1);
+   lua_getfield(L, 1, "handle");
+   if (! lua_isstring(L, -1))
+      goto usage_error;
+   const char *handle = lua_tostring(L, -1);
+   lua_pop(L, 2);
+   lua_replace(L, 1);
+   lua_settop(L, 1);
+   return lua_yaml_encode_impl(L, serializer, handle, prefix);
+}
+
 static int
 l_new(lua_State *L);
 
 static const luaL_Reg yamllib[] = {
    { "encode", l_dump },
+   { "encode_tagged", l_dump_tagged },
    { "decode", l_load },
    { "new",    l_new },
    { NULL, NULL}
-- 
2.15.1 (Apple Git-101)

  parent reply	other threads:[~2018-04-20 13:24 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-04-20 13:24 [PATCH v2 00/10] session: introduce box.session.push Vladislav Shpilevoy
2018-04-20 13:24 ` [PATCH v2 01/10] yaml: don't throw OOM on any error in yaml encoding Vladislav Shpilevoy
2018-05-10 18:10   ` [tarantool-patches] " Konstantin Osipov
2018-04-20 13:24 ` [tarantool-patches] [PATCH v2 10/10] session: introduce binary box.session.push Vladislav Shpilevoy
2018-05-10 19:50   ` Konstantin Osipov
2018-05-24 20:50     ` [tarantool-patches] " Vladislav Shpilevoy
2018-04-20 13:24 ` Vladislav Shpilevoy [this message]
2018-05-10 18:22   ` [tarantool-patches] [PATCH v2 02/10] yaml: introduce yaml.encode_tagged Konstantin Osipov
2018-05-24 20:50     ` [tarantool-patches] " Vladislav Shpilevoy
2018-05-30 19:15       ` Konstantin Osipov
2018-05-30 20:49         ` Vladislav Shpilevoy
2018-05-31 10:46           ` Konstantin Osipov
2018-04-20 13:24 ` [PATCH v2 03/10] yaml: introduce yaml.decode_tag Vladislav Shpilevoy
2018-05-10 18:41   ` [tarantool-patches] " Konstantin Osipov
2018-05-24 20:50     ` [tarantool-patches] " Vladislav Shpilevoy
2018-05-31 10:54       ` Konstantin Osipov
2018-05-31 11:36       ` Konstantin Osipov
2018-04-20 13:24 ` [PATCH v2 04/10] console: use Lua C API to do formatting for console Vladislav Shpilevoy
2018-05-10 18:46   ` [tarantool-patches] " Konstantin Osipov
2018-05-24 20:50     ` [tarantool-patches] " Vladislav Shpilevoy
2018-04-20 13:24 ` [PATCH v2 05/10] session: move salt into iproto connection Vladislav Shpilevoy
2018-05-10 18:47   ` [tarantool-patches] " Konstantin Osipov
2018-04-20 13:24 ` [PATCH v2 06/10] session: introduce session vtab and meta Vladislav Shpilevoy
2018-05-10 19:20   ` [tarantool-patches] " Konstantin Osipov
2018-05-24 20:50     ` [tarantool-patches] " Vladislav Shpilevoy
2018-04-20 13:24 ` [PATCH v2 07/10] port: rename dump() into dump_msgpack() Vladislav Shpilevoy
2018-05-10 19:21   ` [tarantool-patches] " Konstantin Osipov
2018-04-20 13:24 ` [PATCH v2 08/10] session: introduce text box.session.push Vladislav Shpilevoy
2018-05-10 19:27   ` [tarantool-patches] " Konstantin Osipov
2018-05-24 20:50     ` [tarantool-patches] " Vladislav Shpilevoy
2018-04-20 13:24 ` [PATCH v2 09/10] session: enable box.session.push in local console Vladislav Shpilevoy
2018-05-10 19:28   ` [tarantool-patches] " Konstantin Osipov
2018-05-24 20:50 ` [tarantool-patches] [PATCH 1/1] netbox: introduce iterable future objects Vladislav Shpilevoy
2018-06-04 22:17   ` [tarantool-patches] " Vladislav Shpilevoy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=7c30b9483a38bd36425d7e0c87b4d15e8893446e.1524228894.git.v.shpilevoy@tarantool.org \
    --to=v.shpilevoy@tarantool.org \
    --cc=tarantool-patches@freelists.org \
    --cc=vdavydov.dev@gmail.com \
    --subject='Re: [PATCH v2 02/10] yaml: introduce yaml.encode_tagged' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox