1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
/*
* upb - a minimalist implementation of protocol buffers.
*
* Copyright (c) 2014 Google Inc. See LICENSE for details.
* Author: Josh Haberman <jhaberman@gmail.com>
*
* A Lua extension for upb.pb.
*
* Exposes all the types defined in upb/pb/{*}.h
* Also defines a few convenience functions on top.
*/
#include "upb/bindings/lua/upb.h"
#include "upb/pb/decoder.h"
#define LUPB_PBDECODERMETHOD "lupb.pb.decodermethod"
#define MSGDEF_INDEX 1
static upb_pbdecodermethod *lupb_pbdecodermethod_check(lua_State *L, int narg) {
return lupb_refcounted_check(L, narg, LUPB_PBDECODERMETHOD);
}
static int lupb_pbdecodermethod_new(lua_State *L) {
const upb_handlers *handlers = lupb_msg_newwritehandlers(L, 1, &handlers);
upb_pbdecodermethodopts opts;
upb_pbdecodermethodopts_init(&opts, handlers);
const upb_pbdecodermethod *m = upb_pbdecodermethod_new(&opts, &m);
upb_handlers_unref(handlers, &handlers);
lupb_refcounted_pushnewrapper(L, UPB_UPCAST(m), LUPB_PBDECODERMETHOD, &m);
// We need to keep a pointer to the MessageDef (in Lua space) so we can
// construct new messages in parse().
lua_newtable(L);
lua_pushvalue(L, 1);
lua_rawseti(L, -2, MSGDEF_INDEX);
lua_setuservalue(L, -2);
return 1; // The DecoderMethod wrapper.
}
// Unlike most of our exposed Lua functions, this does not correspond to an
// actual method on the underlying DecoderMethod. But it's convenient, and
// important to implement in C because we can do stack allocation and
// initialization of our runtime structures like the Decoder and Sink.
static int lupb_pbdecodermethod_parse(lua_State *L) {
size_t len;
const upb_pbdecodermethod *method = lupb_pbdecodermethod_check(L, 1);
const char *pb = lua_tolstring(L, 2, &len);
const upb_handlers *handlers = upb_pbdecodermethod_desthandlers(method);
lua_getuservalue(L, 1);
lua_rawgeti(L, -1, MSGDEF_INDEX);
lupb_assert(L, !lua_isnil(L, -1));
lupb_msg_pushnew(L, -1); // Push new message.
void *msg = lua_touserdata(L, -1);
// Handlers need this.
lua_getuservalue(L, -1);
upb_pbdecoder decoder;
upb_status status = UPB_STATUS_INIT;
upb_pbdecoder_init(&decoder, method, &status);
upb_sink sink;
upb_sink_reset(&sink, handlers, msg);
upb_pbdecoder_resetoutput(&decoder, &sink);
upb_bufsrc_putbuf(pb, len, upb_pbdecoder_input(&decoder));
// TODO: Our need to call uninit isn't longjmp-safe; what if the decode
// triggers a Lua error? uninit is only needed if the decoder
// dynamically-allocated a growing stack -- ditch this feature and live with
// the compile-time limit? Or have a custom allocation function that
// allocates Lua GC-rooted memory?
upb_pbdecoder_uninit(&decoder);
lupb_checkstatus(L, &status);
lua_pop(L, 1); // Uservalue.
return 1;
}
static const struct luaL_Reg lupb_pbdecodermethod_m[] = {
{"parse", lupb_pbdecodermethod_parse},
{NULL, NULL}
};
static const struct luaL_Reg toplevel_m[] = {
{"DecoderMethod", lupb_pbdecodermethod_new},
{NULL, NULL}
};
int luaopen_upb_pb(lua_State *L) {
luaopen_upb(L);
static char module_key;
if (lupb_openlib(L, &module_key, "upb.pb", toplevel_m)) {
return 1;
}
lupb_register_type(L, LUPB_PBDECODERMETHOD, lupb_pbdecodermethod_m, NULL,
true);
return 1;
}
|