-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsender_capi.h
285 lines (247 loc) · 9.35 KB
/
sender_capi.h
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
#ifndef SENDER_CAPI_H
#define SENDER_CAPI_H
#define SENDER_CAPI_ID_STRING "_capi_sender"
#define SENDER_CAPI_VERSION_MAJOR 1
#define SENDER_CAPI_VERSION_MINOR 0
#define SENDER_CAPI_VERSION_PATCH 0
#ifndef SENDER_CAPI_HAVE_LONG_LONG
# include <limits.h>
# if defined(LLONG_MAX)
# define SENDER_CAPI_HAVE_LONG_LONG 1
# else
# define SENDER_CAPI_HAVE_LONG_LONG 0
# endif
#endif
#ifndef SENDER_CAPI_IMPLEMENT_SET_CAPI
# define SENDER_CAPI_IMPLEMENT_SET_CAPI 0
#endif
#ifndef SENDER_CAPI_IMPLEMENT_GET_CAPI
# define SENDER_CAPI_IMPLEMENT_GET_CAPI 0
#endif
#ifdef __cplusplus
extern "C" {
struct sender_object;
struct sender_reader;
struct sender_capi;
struct sender_capi_value;
#else /* __cplusplus */
typedef struct sender_object sender_object;
typedef struct sender_reader sender_reader;
typedef struct sender_capi sender_capi;
typedef struct sender_capi_value sender_capi_value;
typedef enum sender_capi_value_type sender_capi_value_type;
typedef enum sender_array_type sender_array_type;
#endif /* ! __cplusplus */
enum sender_capi_value_type
{
SENDER_CAPI_TYPE_NONE = 0,
SENDER_CAPI_TYPE_NIL,
SENDER_CAPI_TYPE_BOOLEAN,
SENDER_CAPI_TYPE_INTEGER,
SENDER_CAPI_TYPE_NUMBER,
SENDER_CAPI_TYPE_LIGHTUSERDATA,
SENDER_CAPI_TYPE_CFUNCTION,
SENDER_CAPI_TYPE_STRING,
SENDER_CAPI_TYPE_ARRAY
};
enum sender_array_type
{
SENDER_UCHAR = 1,
SENDER_SCHAR = 2,
SENDER_SHORT = 3,
SENDER_USHORT = 4,
SENDER_INT = 5,
SENDER_UINT = 6,
SENDER_LONG = 7,
SENDER_ULONG = 8,
SENDER_FLOAT = 9,
SENDER_DOUBLE = 10,
#if SENDER_CAPI_HAVE_LONG_LONG
SENDER_LLONG = 11,
SENDER_ULLONG = 12,
#endif
};
struct sender_capi_value
{
sender_capi_value_type type;
union {
int boolVal;
lua_Integer intVal;
lua_Number numVal;
void* ptrVal;
lua_CFunction funcVal;
struct {
const char* ptr;
size_t len;
} strVal;
struct {
sender_array_type type;
size_t elementSize;
size_t elementCount;
const void* data;
} arrayVal;
};
};
/**
* Type for pointer to function that may be called if an error occurs.
* ehdata: void pointer that is given in add/setMsgToSender method (see below)
* msg: detailed error message
* msglen: length of error message
*/
typedef void (*sender_error_handler)(void* ehdata, const char* msg, size_t msglen);
/**
* Sender C API.
*/
struct sender_capi
{
int version_major;
int version_minor;
int version_patch;
/**
* May point to another (incompatible) version of this API implementation.
* NULL if no such implementation exists.
*
* The usage of next_capi makes it possible to implement two or more
* incompatible versions of the C API.
*
* An API is compatible to another API if both have the same major
* version number and if the minor version number of the first API is
* greater or equal than the second one's.
*/
void* next_capi;
/**
* Must return a valid pointer if the object at the given stack
* index is a valid sender object, otherwise must return NULL,
*/
sender_object* (*toSender)(lua_State* L, int index);
/**
* Increase the reference counter of the sender object.
* Must be thread safe.
*/
void (*retainSender)(sender_object* s);
/**
* Decrease the reference counter of the sender object and
* destructs the sender object if no reference is left.
* Must be thread safe.
*/
void (*releaseSender)(sender_object* s);
/**
* Creates new reader object.
* Does not need to be thread safe.
*/
sender_reader* (*newReader)(size_t initialCapacity, float growFactor);
/**
* Destructs reader object.
* Does not need to be thread safe.
*/
void (*freeReader)(sender_reader* r);
/**
* Does not need to be thread safe.
*/
void (*clearReader)(sender_reader* r);
/**
* Does not need to be thread safe.
* Sets out->type to SENDER_CAPI_TYPE_NONE if there is
* no value left.
*/
void (*nextValueFromReader)(sender_reader* r, sender_capi_value* out);
/**
* Must be thread safe.
*
* Gets the next message of a sender into the reader in one atomic step. The
* message is removed from the given sender. If the reader contained older
* message elements from a previous message these are discarded before all messages elements
* from the new message are added to the reader, i.e. after this call the reader contains
* only message elements from the new message.
*
* nonblock: not 0 if function should do nothing if sender cannot send immediately,
* 0 if function should wait for sender to becomde ready.
* timeout time in seconds to wait until a message is available. If negative, waits
* without timeout until next message is available.
* eh: error handling function, may be NULL
* ehdata: additional data that is given to error handling function.
*
* returns: 0 - if next message could be read from the sender
* 1 - if sender is closed. The caller is expected to release the sender.
* Subsequent calls will always result this return code again.
* 2 - if sender was aborted. Subsequent calls may function again. Exact
* context depends on implementation and use case. Normally the caller is
* expected to abort its operation.
* 3 - if next message is not available
* 4 - if reader could not handle the message because the new message
* is larger than the reader's memory limit.
* 5 - if reader has growable memory without limit, but cannot allocate more
* memory because overall memory is exhausted.
*
* All other error codes are implementation specific.
*/
int (*nextMessageFromSender)(sender_object* s, sender_reader* r,
int nonblock, double timeout,
sender_error_handler eh, void* ehdata);
};
#if SENDER_CAPI_IMPLEMENT_SET_CAPI
/**
* Sets the Sender C API into the metatable at the given index.
*
* index: index of the table that is be used as metatable for objects
* that are associated to the given capi.
*/
static int sender_set_capi(lua_State* L, int index, const sender_capi* capi)
{
lua_pushlstring(L, SENDER_CAPI_ID_STRING, strlen(SENDER_CAPI_ID_STRING)); /* -> key */
void** udata = (void**) lua_newuserdata(L, sizeof(void*) + strlen(SENDER_CAPI_ID_STRING) + 1); /* -> key, value */
*udata = (void*)capi;
strcpy((char*)(udata + 1), SENDER_CAPI_ID_STRING); /* -> key, value */
lua_rawset(L, (index < 0) ? (index - 2) : index); /* -> */
return 0;
}
#endif /* SENDER_CAPI_IMPLEMENT_SET_CAPI */
#if SENDER_CAPI_IMPLEMENT_GET_CAPI
/**
* Gives the associated Sender C API for the object at the given stack index.
* Returns NULL, if the object at the given stack index does not have an
* associated Sender C API or only has a Sender C API with incompatible version
* number. If errorReason is not NULL it receives the error reason in this case:
* 1 for incompatible version nummber and 2 for no associated C API at all.
*/
static const sender_capi* sender_get_capi(lua_State* L, int index, int* errorReason)
{
if (luaL_getmetafield(L, index, SENDER_CAPI_ID_STRING) != LUA_TNIL) /* -> _capi */
{
const void** udata = (const void**) lua_touserdata(L, -1); /* -> _capi */
if ( udata
&& (lua_rawlen(L, -1) >= sizeof(void*) + strlen(SENDER_CAPI_ID_STRING) + 1)
&& (memcmp((char*)(udata + 1), SENDER_CAPI_ID_STRING,
strlen(SENDER_CAPI_ID_STRING) + 1) == 0))
{
const sender_capi* capi = (const sender_capi*) *udata; /* -> _capi */
while (capi) {
if ( capi->version_major == SENDER_CAPI_VERSION_MAJOR
&& capi->version_minor >= SENDER_CAPI_VERSION_MINOR)
{ /* -> _capi */
lua_pop(L, 1); /* -> */
return capi;
}
capi = (const sender_capi*) capi->next_capi;
}
if (errorReason) {
*errorReason = 1;
}
} else { /* -> _capi */
if (errorReason) {
*errorReason = 2;
}
} /* -> _capi */
lua_pop(L, 1); /* -> */
} else { /* -> */
if (errorReason) {
*errorReason = 2;
}
} /* -> */
return NULL;
}
#endif /* SENDER_CAPI_IMPLEMENT_GET_CAPI */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* SENDER_CAPI_H */