1#pragma once
2
3#include <stdarg.h>
4
5#include <pw_assert.h>
6#include <pw_branch_optimization.h>
7#include <pw_types.h>
8#include <pw_status.h>
9
10#ifdef __cplusplus
11extern "C" {
12#endif
13
14uint16_t pw_register_interface(char* interface_name, ...);
15/*
16 * Register interface.
17 *
18 * Variadic arguments are method names terminated with nullptr.
19 *
20 * Return global identifier for the interface.
21 */
22
23extern bool pw_interface_exists(uint16_t interface_id);
24/*
25 * Check if interface is registered.
26 */
27
28char* pw_get_interface_name(uint16_t interface_id);
29/*
30 * Get the name of registered interface.
31 */
32
33[[noreturn]]
34void _pw_panic_no_interface(uint16_t type_id, uint16_t interface_id);
35
36PwInterface_Generic* __pw_do_lookup_interface(PwType* type, uint16_t interface_id);
37
38static inline PwInterface_Generic* _pw_lookup_interface_t(PwType* type, uint16_t interface_id)
39{
40 if (_pw_likely(interface_id < PW_NUM_BUILTIN_INTERFACES)) {
41 return type->builtin_interfaces[interface_id];
42 } else {
43 return __pw_do_lookup_interface(type, interface_id);
44 }
45}
46
47static inline PwInterface_Generic* _pw_lookup_interface(uint16_t type_id, uint16_t interface_id)
48{
49 return _pw_lookup_interface_t(_pw_types[type_id], interface_id);
50}
51
52#define pw_lookup_interface(type_id, interface_name) \
53 ( \
54 (PwInterface_##interface_name*) \
55 _pw_lookup_interface((type_id), PwInterfaceId_##interface_name) \
56 )
57
58static inline PwInterface_Generic* pw_get_interface(uint16_t type_id, uint16_t interface_id)
59{
60 PwInterface_Generic* result = _pw_lookup_interface(type_id, interface_id);
61 if (_pw_likely(result)) {
62 return result;
63 }
64 _pw_panic_no_interface(type_id, interface_id);
65}
66
67static inline bool _pw_has_interface(uint16_t type_id, uint16_t interface_id)
68{
69 return (bool) _pw_lookup_interface(type_id, interface_id);
70}
71
72#define pw_method(type_id, interface_name, method_name, result) \
73 __extension__ \
74 ({ \
75 PwInterface_##interface_name* iface = (PwInterface_##interface_name*) \
76 _pw_lookup_interface((type_id), PwInterfaceId_##interface_name); \
77 if (_pw_likely(iface)) { \
78 *(result) = &iface->method_name; \
79 } else { \
80 pw_set_status(PwStatus(PweInterfaceNotDefined)); \
81 *(result) = nullptr; \
82 } \
83 (bool) iface; \
84 })
85
86#define pw_call(interface_name, method_name, self, ...) \
87 __extension__ \
88 ({ \
89 PwMethod_##interface_name##_##method_name* meth; \
90 bool ret = pw_method((self)->type_id, interface_name, method_name, &meth); \
91 if (_pw_likely(ret)) { \
92 ret = meth->func(meth, (self) __VA_OPT__(,) __VA_ARGS__); \
93 } \
94 ret; \
95 })
96
97#define pw_call2(interface, method_name, ...) \
98 __extension__ \
99 ({ \
100 auto meth = &(interface)->method_name; \
101 meth->func(meth __VA_OPT__(,) __VA_ARGS__); \
102 })
103
104#define pw_super(mthis, ...) \
105 __extension__ \
106 ({ \
107 auto meth = (mthis)->super; \
108 meth->func(meth __VA_OPT__(,) __VA_ARGS__); \
109 })
110
111// the following macro may call only methods of the same interface; use pw_call for other methods
112#define pw_super_call(method_name, mthis, ...) \
113 __extension__ \
114 ({ \
115 auto meth = &(mthis)->super->self->method_name; \
116 meth->func(meth __VA_OPT__(,) __VA_ARGS__); \
117 })
118
119// the following macro may call only methods of the same interface; use pw_call for other methods
120#define pw_this_call(method_name, mthis, ...) \
121 __extension__ \
122 ({ \
123 auto meth = &(mthis)->self->method_name; \
124 meth->func(meth __VA_OPT__(,) __VA_ARGS__); \
125 })
126
127
128/****************************************************************
129 * Basic interface
130 *
131 * Methods `destroy`, `clone`, `decref`, and `deepcopy` are optional and can be nullptr.
132 */
133
134// forward declaration, hash context is defined in src/pw_hash.c:
135PW_STRUCT(PwHashContext);
136
137// constructor arguments
138
139PW_STRUCT(PwCtorArgs) {
140 PwCtorArgs* next;
141 uint16_t type_id;
142 // variable part follows
143};
144
145static inline void* pw_get_ctor_args(uint16_t type_id, PwCtorArgs* ctor_args)
146/*
147 * Return pointer to the type-specific args or nullptr.
148 * The result is void* to avoid cumbersome typecasts.
149 */
150{
151 while (ctor_args) {
152 if (ctor_args->type_id == type_id) {
153 return (void*) ctor_args;
154 }
155 ctor_args = ctor_args->next;
156 }
157 return nullptr;
158}
159
160#define pw_this_ctor_args() pw_get_ctor_args(mthis->type_id, ctor_args)
161
162
163PW_METHOD_BEGIN(Basic, create)
164 bool (*PwFunc_Basic_create)(PwMethod_Basic_create* mthis, PwValuePtr result, PwCtorArgs* ctor_args)
165PW_METHOD_END(Basic, create)
166/*
167 * Initialize result with either with default value or with value provided
168 * in ctor_args.
169 *
170 * Upon call the result is initialized with desired type which can be different
171 * if inherited constructor is used.
172 * All other fields are guaranteed to be zeros.
173 *
174 * As long as ctor_args is different for different types, extra care
175 * should be taken when handling it.
176 *
177 * The method must call super method first, because super method
178 * usually allocates memory.
179 *
180 * If an error occurs during initialization, this method should call pw_destroy(result)
181 * and return false.
182 */
183
184PW_METHOD_BEGIN(Basic, destroy)
185 bool (*PwFunc_Basic_destroy)(PwMethod_Basic_destroy* mthis, PwValuePtr self, _PwCompoundChain* tail)
186PW_METHOD_END(Basic, destroy)
187/*
188 * Optional method.
189 *
190 * Delete all associated resources and call super method.
191 *
192 * Always return true.
193 */
194
195PW_METHOD_BEGIN(Basic, is_immutable)
196 bool (*PwFunc_Basic_is_immutable)(PwMethod_Basic_is_immutable* mthis, PwValuePtr self)
197PW_METHOD_END(Basic, is_immutable)
198/*
199 * Optional method.
200 *
201 * A type must implement it to prove its immutability.
202 */
203
204PW_METHOD_BEGIN(Basic, clone)
205 bool (*PwFunc_Basic_clone)(PwMethod_Basic_clone* mthis, PwValuePtr self)
206PW_METHOD_END(Basic, clone)
207/*
208 * Optional method.
209 *
210 * This method is called after other value is copied to `self`.
211 * If `self` has reference counted allocated data, this method increments reference count.
212 *
213 * future: If `self` has immutable allocated data, this method has the same behavior as deepcopy.
214 *
215 * This method never fails for reference counted data.
216 */
217
218PW_METHOD_BEGIN(Basic, decref)
219 bool (*PwFunc_Basic_decref)(PwMethod_Basic_decref* mthis, PwValuePtr self)
220PW_METHOD_END(Basic, decref)
221/*
222 * Mandatory method if reference count is used and circular references are possible.
223 * Optional otherwise.
224 *
225 * Decrement reference count and return true if it is still nonzero.
226 */
227
228PW_METHOD_BEGIN(Basic, hash)
229 bool (*PwFunc_Basic_hash)(PwMethod_Basic_hash* mthis, PwValuePtr self, PwHashContext* ctx, _PwCompoundChain* tail)
230PW_METHOD_END(Basic, hash)
231/*
232 * Calculate hash of the value.
233 *
234 * Hashes are used by Map and the implementation of this method
235 * determines its weirdness, e.g. whether float 1.0 is same
236 * as integer 1 as in python, or not.
237 *
238 * The basic rule is to allow type variations.
239 * I.e. if a hash method involves type id, it should use constant id
240 * of the type it is defined for, not self->type_id.
241 *
242 * Always return true.
243 */
244
245PW_METHOD_BEGIN(Basic, deepcopy)
246 bool (*PwFunc_Basic_deepcopy)(PwMethod_Basic_deepcopy* mthis, PwValuePtr self, PwValuePtr result, _PwCompoundChain* tail)
247PW_METHOD_END(Basic, deepcopy)
248/*
249 * Optional method.
250 *
251 * Upon call the result is initialized with desired type which can be different
252 * if inherited constructor is used.
253 * All other fields are guaranteed to be zeros.
254 *
255 * This method should create a deep copy of self.
256 * In case of failure the result should be Null.
257 */
258
259PW_METHOD_BEGIN(Basic, dump)
260 bool (*PwFunc_Basic_dump)(PwMethod_Basic_dump* mthis, PwValuePtr self, FILE* fp, int indent, _PwCompoundChain* tail)
261PW_METHOD_END(Basic, dump)
262/*
263 * Dump self to fp.
264 *
265 * Always return true.
266 */
267
268PW_METHOD_BEGIN(Basic, equal)
269 bool (*PwFunc_Basic_equal)(PwMethod_Basic_equal* mthis, PwValuePtr self, PwValuePtr other, _PwCompoundChain* tail)
270PW_METHOD_END(Basic, equal)
271/*
272 * Compare for equality.
273 */
274
275PW_METHOD_BEGIN(Basic, to_string)
276 bool (*PwFunc_Basic_to_string)(PwMethod_Basic_to_string* mthis, PwValuePtr self, PwValuePtr result, _PwCompoundChain* tail)
277PW_METHOD_END(Basic, to_string)
278/*
279 * XXX this must be a separate interface for string formatting
280 */
281
282PW_METHOD_BEGIN(Basic, is_true)
283 bool (*PwFunc_Basic_is_true)(PwMethod_Basic_is_true* mthis, PwValuePtr self, _PwCompoundChain* tail)
284PW_METHOD_END(Basic, is_true)
285/*
286 * XXX move to Logic interface
287 */
288
289typedef void (*PwCallback_OnChild)(PwValuePtr child, _PwCompoundChain* tail, void* udata);
290/*
291 * Callback type for PwFunc_Basic_iter_children.
292 * Parent is tail->value
293 */
294
295PW_METHOD_BEGIN(Basic, iter_children)
296 bool (*PwFunc_Basic_iter_children)(PwMethod_Basic_iter_children* mthis, PwValuePtr self,
297 _PwCompoundChain* tail, PwCallback_OnChild on_child, void* udata)
298PW_METHOD_END(Basic, iter_children)
299/*
300 * Iterate compound children that may be involved in circular references.
301 *
302 * Always return true.
303 */
304
305#define PW_BASIC_INTERFACE_METHODS \
306 X(create, 1) \
307 X(destroy, 1) \
308 X(is_immutable, 1) \
309 X(clone, 1) \
310 X(decref, 1) \
311 X(hash, 1) \
312 X(deepcopy, 1) \
313 X(dump, 1) \
314 X(equal, 1) \
315 X(to_string, 1) \
316 X(is_true, 1) \
317 X(iter_children)
318
319PW_INTERFACE_BEGIN(Basic)
320#define X(name, ...) PwMethod_Basic_##name name;
321 PW_BASIC_INTERFACE_METHODS
322#undef X
323PW_INTERFACE_END(Basic)
324
325/*
326 * Basic functions
327 */
328
329#define pw_create(type_id, result) pw_create2((type_id), nullptr, (result))
330
331[[nodiscard]] static inline bool pw_create2(uint16_t type_id, void* ctor_args, PwValuePtr result)
332{
333 pw_destroy(result);
334 result->type_id = type_id;
335 return pw_call(Basic, create, result, ctor_args);
336}
337
338static inline void __pw_clone(PwValuePtr result, PwValuePtr value)
339/*
340 * Helper function for pw_clone and pw_clone2.
341 */
342{
343 *result = *value;
344 if (_pw_likely(value->type_id < PW_NUM_INTEGRAL_TYPES)) {
345 return;
346 }
347 PwMethod_Basic_clone* mthis;
348 if (pw_method(value->type_id, Basic, clone, &mthis)) {
349 PwFunc_Basic_clone fn = mthis->func;
350 if (_pw_unlikely(fn)) {
351 fn(mthis, result);
352 }
353 }
354}
355
356[[nodiscard]] static inline _PwValue pw_clone(PwValuePtr value)
357/*
358 * Single argument version, return PwValue.
359 * Useful for use as initializer of as an argument for variadic functions
360 * that accept PwValues (i.e. not PwValuePtr)
361 * such as pw_array, pw_array_append, pw_map, pw_map_update.
362 */
363{
364 _PwValue result = PW_NULL;
365 __pw_clone(&result, value);
366 return result;
367}
368
369static inline void pw_clone2(PwValuePtr result, PwValuePtr value)
370/*
371 * Two arguments version.
372 * `result` is destroyed before cloning.
373 */
374{
375 pw_destroy(result);
376 __pw_clone(result, value);
377}
378
379[[nodiscard]] static inline bool pw_deepcopy(PwValuePtr result, PwValuePtr value)
380{
381 if (_pw_likely(value->type_id < PW_NUM_INTEGRAL_TYPES)) {
382 *result = *value;
383 return true;
384 }
385 PwMethod_Basic_deepcopy* mthis;
386 if (!pw_method(value->type_id, Basic, deepcopy, &mthis)) {
387 return false;
388 }
389 PwFunc_Basic_deepcopy fn = mthis->func;
390 if (_pw_unlikely(fn)) {
391 return fn(mthis, value, result, nullptr);
392 } else {
393 pw_destroy(result);
394 *result = *value;
395 return true;
396 }
397}
398
399static inline bool _pw_call_is_immutable(PwValuePtr value)
400{
401 PwMethod_Basic_is_immutable* mthis;
402 if (pw_method(value->type_id, Basic, is_immutable, &mthis)) {
403 PwFunc_Basic_is_immutable fn = mthis->func;
404 if (_pw_unlikely(fn)) {
405 return fn(mthis, value);
406 }
407 }
408 return false;
409}
410
411static inline bool pw_is_immutable(PwValuePtr value)
412{
413 if (_pw_likely(value->type_id < PW_NUM_IMMUTABLE_TYPES)) {
414 return true;
415 }
416 return _pw_call_is_immutable(value);
417}
418
419static inline bool pw_is_true(PwValuePtr value)
420{
421 return pw_call(Basic, is_true, value, nullptr);
422}
423
424[[nodiscard]] static inline bool pw_to_string(PwValuePtr value, PwValuePtr result)
425{
426 return pw_call(Basic, to_string, value, result, nullptr);
427}
428
429/*
430 * Compare for equality.
431 */
432
433[[nodiscard]] static inline bool _pw_basic_eq(PwValuePtr a, PwValuePtr b)
434{
435 if (a == b) {
436 // compare with self
437 return true;
438 }
439 if (a->u64[0] == b->u64[0] && a->u64[1] == b->u64[1]) {
440 // quick comparison
441 return true;
442 }
443 return false;
444}
445
446[[nodiscard]] static inline bool _pw_equal(PwValuePtr a, PwValuePtr b)
447{
448 if (_pw_basic_eq(a, b)) {
449 return true;
450 } else {
451 return pw_call(Basic, equal, a, b, nullptr);
452 }
453}
454
455[[nodiscard]] static inline bool _pw_equal_r(PwValuePtr a, PwValuePtr b, _PwCompoundChain* tail)
456{
457 if (_pw_basic_eq(a, b)) {
458 return true;
459 } else {
460 return pw_call(Basic, equal, a, b, tail);
461 }
462}
463
464/*
465 * Type-generic compare for equality.
466 */
467
468#define pw_equal(a, b) _Generic((b), \
469 nullptr_t: _pw_equal_null, \
470 bool: _pw_equal_bool, \
471 char: _pw_equal_char, \
472 unsigned char: _pw_equal_uchar, \
473 short: _pw_equal_short, \
474 unsigned short: _pw_equal_ushort, \
475 int: _pw_equal_int, \
476 unsigned int: _pw_equal_uint, \
477 long: _pw_equal_long, \
478 unsigned long: _pw_equal_ulong, \
479 long long: _pw_equal_longlong, \
480 unsigned long long: _pw_equal_ulonglong, \
481 float: _pw_equal_float, \
482 double: _pw_equal_double, \
483 char*: _pw_equal_ascii, \
484 char8_t*: _pw_equal_utf8, \
485 char32_t*: _pw_equal_utf32, \
486 PwValuePtr: _pw_equal \
487 )((a), (b))
488
489[[nodiscard]] static inline bool _pw_equal_null (PwValuePtr a, nullptr_t b) { return pw_is_null(a); }
490[[nodiscard]] static inline bool _pw_equal_bool (PwValuePtr a, bool b) { _PwValue v = PW_BOOL(b); return _pw_equal(a, &v); }
491[[nodiscard]] static inline bool _pw_equal_char (PwValuePtr a, char b) { _PwValue v = PW_SIGNED(b); return _pw_equal(a, &v); }
492[[nodiscard]] static inline bool _pw_equal_uchar (PwValuePtr a, unsigned char b) { _PwValue v = PW_UNSIGNED(b); return _pw_equal(a, &v); }
493[[nodiscard]] static inline bool _pw_equal_short (PwValuePtr a, short b) { _PwValue v = PW_SIGNED(b); return _pw_equal(a, &v); }
494[[nodiscard]] static inline bool _pw_equal_ushort (PwValuePtr a, unsigned short b) { _PwValue v = PW_UNSIGNED(b); return _pw_equal(a, &v); }
495[[nodiscard]] static inline bool _pw_equal_int (PwValuePtr a, int b) { _PwValue v = PW_SIGNED(b); return _pw_equal(a, &v); }
496[[nodiscard]] static inline bool _pw_equal_uint (PwValuePtr a, unsigned int b) { _PwValue v = PW_UNSIGNED(b); return _pw_equal(a, &v); }
497[[nodiscard]] static inline bool _pw_equal_long (PwValuePtr a, long b) { _PwValue v = PW_SIGNED(b); return _pw_equal(a, &v); }
498[[nodiscard]] static inline bool _pw_equal_ulong (PwValuePtr a, unsigned long b) { _PwValue v = PW_UNSIGNED(b); return _pw_equal(a, &v); }
499[[nodiscard]] static inline bool _pw_equal_longlong (PwValuePtr a, long long b) { _PwValue v = PW_SIGNED(b); return _pw_equal(a, &v); }
500[[nodiscard]] static inline bool _pw_equal_ulonglong(PwValuePtr a, unsigned long long b) { _PwValue v = PW_UNSIGNED(b); return _pw_equal(a, &v); }
501[[nodiscard]] static inline bool _pw_equal_float (PwValuePtr a, float b) { _PwValue v = PW_FLOAT(b); return _pw_equal(a, &v); }
502[[nodiscard]] static inline bool _pw_equal_double (PwValuePtr a, double b) { _PwValue v = PW_FLOAT(b); return _pw_equal(a, &v); }
503
504[[nodiscard]] bool _pw_string_eq_z(PwValuePtr a, void* b, uint8_t b_char_size);
505
506[[nodiscard]] static inline bool _pw_equal_ascii(PwValuePtr a, char* b)
507{
508 return _pw_string_eq_z(a, b, 1);
509}
510[[nodiscard]] static inline bool _pw_equal_utf8(PwValuePtr a, char8_t* b)
511{
512 return _pw_string_eq_z(a, b, 0);
513}
514[[nodiscard]] static inline bool _pw_equal_utf32(PwValuePtr a, char32_t* b)
515{
516 return _pw_string_eq_z(a, b, 4);
517}
518
519/****************************************************************
520 * RandomAccess interface
521 *
522 * Methods that accept key argument may convert it from String
523 * to number if items are accessible by numeric index.
524 */
525
526PW_METHOD_BEGIN(RandomAccess, length)
527 bool (*PwFunc_RandomAccess_length)(PwMethod_RandomAccess_length* mthis, PwValuePtr self, unsigned* result)
528PW_METHOD_END(RandomAccess, length)
529
530PW_METHOD_BEGIN(RandomAccess, get_item)
531 bool (*PwFunc_RandomAccess_get_item)(PwMethod_RandomAccess_get_item* mthis, PwValuePtr self, PwValuePtr key, PwValuePtr result)
532PW_METHOD_END(RandomAccess, get_item)
533
534PW_METHOD_BEGIN(RandomAccess, get_item_s)
535 bool (*PwFunc_RandomAccess_get_item_s)(PwMethod_RandomAccess_get_item_s* mthis, PwValuePtr self, ssize_t key, PwValuePtr result)
536PW_METHOD_END(RandomAccess, get_item_s)
537
538PW_METHOD_BEGIN(RandomAccess, get_item_u)
539 bool (*PwFunc_RandomAccess_get_item_u)(PwMethod_RandomAccess_get_item_u* mthis, PwValuePtr self, unsigned key, PwValuePtr result)
540PW_METHOD_END(RandomAccess, get_item_u)
541
542PW_METHOD_BEGIN(RandomAccess, set_item)
543 bool (*PwFunc_RandomAccess_set_item)(PwMethod_RandomAccess_set_item* mthis, PwValuePtr self, PwValuePtr key, PwValuePtr value)
544PW_METHOD_END(RandomAccess, set_item)
545
546PW_METHOD_BEGIN(RandomAccess, set_item_s)
547 bool (*PwFunc_RandomAccess_set_item_s)(PwMethod_RandomAccess_set_item_s* mthis, PwValuePtr self, ssize_t key, PwValuePtr value)
548PW_METHOD_END(RandomAccess, set_item_s)
549
550PW_METHOD_BEGIN(RandomAccess, set_item_u)
551 bool (*PwFunc_RandomAccess_set_item_u)(PwMethod_RandomAccess_set_item_u* mthis, PwValuePtr self, unsigned key, PwValuePtr value)
552PW_METHOD_END(RandomAccess, set_item_u)
553
554PW_METHOD_BEGIN(RandomAccess, delete_item)
555 bool (*PwFunc_RandomAccess_delete_item)(PwMethod_RandomAccess_delete_item* mthis, PwValuePtr self, PwValuePtr key)
556PW_METHOD_END(RandomAccess, delete_item)
557
558PW_METHOD_BEGIN(RandomAccess, delete_item_s)
559 bool (*PwFunc_RandomAccess_delete_item_s)(PwMethod_RandomAccess_delete_item_s* mthis, PwValuePtr self, ssize_t key)
560PW_METHOD_END(RandomAccess, delete_item_s)
561
562PW_METHOD_BEGIN(RandomAccess, delete_item_u)
563 bool (*PwFunc_RandomAccess_delete_item_u)(PwMethod_RandomAccess_delete_item_u* mthis, PwValuePtr self, unsigned key)
564PW_METHOD_END(RandomAccess, delete_item_u)
565
566PW_METHOD_BEGIN(RandomAccess, pop_item)
567 bool (*PwFunc_RandomAccess_pop_item)(PwMethod_RandomAccess_pop_item* mthis, PwValuePtr self, PwValuePtr result)
568PW_METHOD_END(RandomAccess, pop_item)
569
570#define PW_RANDOM_ACCESS_INTERFACE_METHODS \
571 X(length, 1) \
572 X(get_item, 1) \
573 X(get_item_s, 1) \
574 X(get_item_u, 1) \
575 X(set_item, 1) \
576 X(set_item_s, 1) \
577 X(set_item_u, 1) \
578 X(delete_item, 1) \
579 X(delete_item_s, 1) \
580 X(delete_item_u, 1) \
581 X(pop_item)
582
583PW_INTERFACE_BEGIN(RandomAccess)
584#define X(name, ...) PwMethod_RandomAccess_##name name;
585 PW_RANDOM_ACCESS_INTERFACE_METHODS
586#undef X
587PW_INTERFACE_END(RandomAccess)
588
589
590/****************************************************************
591 * Reader interface
592 */
593
594// XXX synchronous method, need to make it asynchronous
595PW_METHOD_BEGIN(Reader, read)
596 bool (*PwFunc_Reader_read)(PwMethod_Reader_read* mthis, PwValuePtr self, void* buffer, unsigned buffer_size, unsigned* bytes_read)
597PW_METHOD_END(Reader, read)
598
599#define PW_READER_INTERFACE_METHODS \
600 X(read)
601
602PW_INTERFACE_BEGIN(Reader)
603#define X(name, ...) PwMethod_Reader_##name name;
604 PW_READER_INTERFACE_METHODS
605#undef X
606PW_INTERFACE_END(Reader)
607
608
609/****************************************************************
610 * Writer interface
611 */
612
613// XXX synchronous method, need to make it asynchronous
614PW_METHOD_BEGIN(Writer, write)
615 bool (*PwFunc_Writer_write)(PwMethod_Writer_write* mthis, PwValuePtr self, void* data, unsigned size, unsigned* bytes_written)
616PW_METHOD_END(Writer, write)
617
618#define PW_WRITER_INTERFACE_METHODS \
619 X(write)
620
621PW_INTERFACE_BEGIN(Writer)
622#define X(name, ...) PwMethod_Writer_##name name;
623 PW_WRITER_INTERFACE_METHODS
624#undef X
625PW_INTERFACE_END(Writer)
626
627
628/****************************************************************
629 * LineReader interface
630 */
631
632PW_METHOD_BEGIN(LineReader, start)
633 bool (*PwFunc_LineReader_start)(PwMethod_LineReader_start* mthis, PwValuePtr self)
634PW_METHOD_END(LineReader, start)
635/*
636 * Prepare to read lines.
637 *
638 * Basically, any value that implements LineReader interface
639 * must be prepared to read lines without making this call.
640 *
641 * Calling this method again should reset line reader.
642 */
643
644PW_METHOD_BEGIN(LineReader, read_line)
645 bool (*PwFunc_LineReader_read_line)(PwMethod_LineReader_read_line* mthis, PwValuePtr self, PwValuePtr result)
646PW_METHOD_END(LineReader, read_line)
647/*
648 * Read next line.
649 *
650 * XXX synchronous method, need to make it asynchronous
651 */
652
653PW_METHOD_BEGIN(LineReader, read_line_inplace)
654 bool (*PwFunc_LineReader_read_line_inplace)(PwMethod_LineReader_read_line_inplace* mthis, PwValuePtr self, PwValuePtr line)
655PW_METHOD_END(LineReader, read_line_inplace)
656/*
657 * Truncate line and read next line into it.
658 * Return true if read some data, false if error or eof.
659 *
660 * This makes sense for files, but for string list it destroys line and clones nexr one into it.
661 *
662 * XXX synchronous method, need to make it asynchronous
663 */
664
665PW_METHOD_BEGIN(LineReader, unread_line)
666 bool (*PwFunc_LineReader_unread_line)(PwMethod_LineReader_unread_line* mthis, PwValuePtr self, PwValuePtr line)
667PW_METHOD_END(LineReader, unread_line)
668/*
669 * Push line back to the reader.
670 * Only one pushback is guaranteed.
671 * Return false if pushback buffer is full.
672 */
673
674PW_METHOD_BEGIN(LineReader, get_line_number)
675 bool (*PwFunc_LineReader_get_line_number)(PwMethod_LineReader_get_line_number* mthis, PwValuePtr self, unsigned* result)
676PW_METHOD_END(LineReader, get_line_number)
677/*
678 * Return current line number, 1-based.
679 */
680
681PW_METHOD_BEGIN(LineReader, stop)
682 bool (*PwFunc_LineReader_stop)(PwMethod_LineReader_stop* mthis, PwValuePtr self)
683PW_METHOD_END(LineReader, stop)
684/*
685 * Free internal buffer.
686 *
687 * Always return true.
688 */
689
690#define PW_LINE_READER_INTERFACE_METHODS \
691 X(start, 1) \
692 X(read_line, 1) \
693 X(read_line_inplace, 1) \
694 X(unread_line, 1) \
695 X(get_line_number, 1) \
696 X(stop)
697
698PW_INTERFACE_BEGIN(LineReader)
699#define X(name, ...) PwMethod_LineReader_##name name;
700 PW_LINE_READER_INTERFACE_METHODS
701#undef X
702PW_INTERFACE_END(LineReader)
703
704
705/****************************************************************
706 * Append interface
707 */
708
709// XXX may block on files, need to make it asynchronous
710PW_METHOD_BEGIN(Append, append)
711 bool (*PwFunc_Append_append)(PwMethod_Append_append* mthis, PwValuePtr self, PwValuePtr value)
712PW_METHOD_END(Append, append)
713
714// XXX may block on files, need to make it asynchronous
715PW_METHOD_BEGIN(Append, append_string_data)
716 bool (*PwFunc_Append_append_string_data)(PwMethod_Append_append_string_data* mthis,
717 PwValuePtr self, uint8_t* start_ptr, uint8_t* end_ptr, uint8_t char_size)
718PW_METHOD_END(Append, append_string_data)
719
720#define PW_APPEND_INTERFACE_METHODS \
721 X(append, 1) \
722 X(append_string_data)
723
724PW_INTERFACE_BEGIN(Append)
725#define X(name, ...) PwMethod_Append_##name name;
726 PW_APPEND_INTERFACE_METHODS
727#undef X
728PW_INTERFACE_END(Append)
729
730
731/****************************************************************
732 * File descriptor interface
733 */
734
735PW_METHOD_BEGIN(Fd, get_fd)
736 bool (*PwFunc_Fd_get_fd)(PwMethod_Fd_get_fd* mthis, PwValuePtr self, int* result)
737PW_METHOD_END(Fd, get_fd)
738/*
739 * Writes file descriptor or -1 to the result.
740 */
741
742PW_METHOD_BEGIN(Fd, set_fd)
743 bool (*PwFunc_Fd_set_fd)(PwMethod_Fd_set_fd* mthis, PwValuePtr self, int fd, bool take_ownership)
744PW_METHOD_END(Fd, set_fd)
745/*
746 * Set file descriptor obtained elsewhere.
747 * If `take_ownership` is true, File takes the ownership and fd will be closed by `close` method.
748 */
749
750PW_METHOD_BEGIN(Fd, close)
751 bool (*PwFunc_Fd_close)(PwMethod_Fd_close* mthis, PwValuePtr self)
752PW_METHOD_END(Fd, close)
753/*
754 * Close file descriptor unless it was set with no ownership transfer.
755 */
756
757PW_METHOD_BEGIN(Fd, set_nonblocking)
758 bool (*PwFunc_Fd_set_nonblocking)(PwMethod_Fd_set_nonblocking* mthis, PwValuePtr self, bool mode)
759PW_METHOD_END(Fd, set_nonblocking)
760/*
761 * Set/reset nonblocking mode for file descriptor.
762 */
763
764#define PW_FD_INTERFACE_METHODS \
765 X(get_fd, 1) \
766 X(set_fd, 1) \
767 X(close, 1) \
768 X(set_nonblocking)
769
770PW_INTERFACE_BEGIN(Fd)
771#define X(name, ...) PwMethod_Fd_##name name;
772 PW_FD_INTERFACE_METHODS
773#undef X
774PW_INTERFACE_END(Fd)
775
776
777/****************************************************************
778 * Shorthand functions
779 */
780
781[[nodiscard]] static inline bool pw_read(PwValuePtr reader, void* buffer, unsigned buffer_size, unsigned* bytes_read)
782{
783 return pw_call(Reader, read, reader, buffer, buffer_size, bytes_read);
784}
785
786[[nodiscard]] static inline bool pw_write(PwValuePtr writer, void* data, unsigned size, unsigned* bytes_written)
787{
788 return pw_call(Writer, write, writer, data, size, bytes_written);
789}
790
791[[nodiscard]] static inline bool pw_append(PwValuePtr container, PwValuePtr value)
792{
793 return pw_call(Append, append, container, value);
794}
795
796[[nodiscard]] static inline int pw_get_fd(PwValuePtr value)
797{
798 int fd = -1;
799 if (!pw_call(Fd, get_fd, value, &fd)) { /* ignore return value, it's always true */ }
800 return fd;
801}
802
803[[nodiscard]] static inline bool pw_set_fd(PwValuePtr value, int fd, bool take_ownership)
804{
805 return pw_call(Fd, set_fd, value, fd, take_ownership);
806}
807
808[[nodiscard]] static inline bool pw_set_nonblocking(PwValuePtr value, bool mode)
809{
810 return pw_call(Fd, set_nonblocking, value, mode);
811}
812
813static inline void pw_close(PwValuePtr value)
814/*
815 * This wrapper does not check the result of close and preserves the status of current task
816 */
817{
818 PwValue status = pw_get_status();
819 if (!pw_call(Fd, close, value)) { /* no op */ }
820 pw_set_status(&status);
821}
822
823[[nodiscard]] static inline bool pw_start_read_lines(PwValuePtr reader)
824{
825 return pw_call(LineReader, start, reader);
826}
827
828[[nodiscard]] static inline bool pw_read_line(PwValuePtr reader, PwValuePtr result)
829{
830 return pw_call(LineReader, read_line, reader, result);
831}
832
833[[nodiscard]] static inline bool pw_read_line_inplace(PwValuePtr reader, PwValuePtr line)
834{
835 return pw_call(LineReader, read_line_inplace, reader, line);
836}
837
838[[nodiscard]] static inline bool pw_unread_line(PwValuePtr reader, PwValuePtr line)
839{
840 return pw_call(LineReader, unread_line, reader, line);
841}
842
843[[nodiscard]] static inline unsigned pw_get_line_number(PwValuePtr reader)
844{
845 unsigned result = 0;
846 if (!pw_call(LineReader, get_line_number, reader, &result)) { /* ignore return value, it's always true */ }
847 return result;
848}
849
850static inline void pw_stop_read_lines(PwValuePtr reader)
851{
852 if (!pw_call(LineReader, stop, reader)) { /* ignore return value, it's always true */ }
853}
854
855#ifdef __cplusplus
856}
857#endif