1#pragma once
  2
  3#include <errno.h>
  4#include <stddef.h>
  5#include <stdint.h>
  6#include <stdio.h>
  7#include <string.h>
  8#include <uchar.h>
  9
 10#include <libpussy/allocator.h>
 11
 12#include <pw_assert.h>
 13#include <pw_branch_optimization.h>
 14#include <pw_helper_macros.h>
 15#include <pw_interfaces_base.h>
 16
 17#ifdef __cplusplus
 18extern "C" {
 19#endif
 20
 21// automatically cleaned value
 22#define _PW_VALUE_CLEANUP [[ gnu::cleanup(pw_destroy) ]]
 23#define PwValue _PW_VALUE_CLEANUP _PwValue
 24
 25// Built-in types
 26#define PwTypeId_Null           0
 27#define PwTypeId_Bool           1U
 28#define PwTypeId_Int            2U  // abstract integer
 29#define PwTypeId_Signed         3U  // subtype of int, signed integer
 30#define PwTypeId_Unsigned       4U  // subtype of int, unsigned integer
 31#define PwTypeId_Float          5U
 32#define PwTypeId_DateTime       6U
 33#define PwTypeId_Timestamp      7U
 34#define PwTypeId_Ptr            8U  // container for void*
 35#define PwTypeId_Status         9U
 36
 37#define PW_NUM_INTEGRAL_TYPES  10   // integral types have no allocated data so they do not have destructor, and are immutable
 38
 39#define PwTypeId_String        10U
 40
 41#define PW_NUM_IMMUTABLE_TYPES 11   // all integral types and String type are immutable;
 42                                    // other types must implement `is_immutable` method to prove that
 43
 44#define PwTypeId_Struct        11U  // base type for reference counted allocated data
 45#define PwTypeId_Compound      12U  // mixin for values that may contain circular references
 46#define PwTypeId_Exception     13U
 47#define PwTypeId_BasicArray    14U
 48#define PwTypeId_Array         15U
 49#define PwTypeId_BasicSet      16U
 50#define PwTypeId_Set           17U
 51#define PwTypeId_BasicMap      18U
 52#define PwTypeId_Map           19U
 53#define PwTypeId_Sync          20U  // abstract base type for all synchronization objects
 54#define PwTypeId_Task          21U  // awaitable task
 55#define PwTypeId_ChldTasks     22U  // awaitable children tasks
 56#define PwTypeId_Mutex         23U
 57#define PwTypeId_CV            24U  // condition variable
 58
 59#define PW_NUM_BUILTIN_TYPES   25
 60
 61// limits
 62#define PW_SIGNED_MAX    0x7fff'ffff'ffff'ffffLL
 63#define PW_UNSIGNED_MAX  0xffff'ffff'ffff'ffffULL
 64
 65// type checking
 66
 67// Note: there's no type checking functions for basic array, set, and map.
 68// Having such separate macros is error-prone.
 69#define pw_is_null(value)           pw_is_subtype((value), PwTypeId_Null)
 70#define pw_is_bool(value)           pw_is_subtype((value), PwTypeId_Bool)
 71#define pw_is_int(value)            pw_is_subtype((value), PwTypeId_Int)
 72#define pw_is_signed(value)         pw_is_subtype((value), PwTypeId_Signed)
 73#define pw_is_unsigned(value)       pw_is_subtype((value), PwTypeId_Unsigned)
 74#define pw_is_float(value)          pw_is_subtype((value), PwTypeId_Float)
 75#define pw_is_datetime(value)       pw_is_subtype((value), PwTypeId_DateTime)
 76#define pw_is_timestamp(value)      pw_is_subtype((value), PwTypeId_Timestamp)
 77#define pw_is_ptr(value)            pw_is_subtype((value), PwTypeId_Ptr)
 78#define pw_is_status(value)         pw_is_subtype((value), PwTypeId_Status)
 79#define pw_is_string(value)         pw_is_subtype((value), PwTypeId_String)
 80#define pw_is_struct(value)         pw_is_subtype((value), PwTypeId_Struct)
 81#define pw_is_compound(value)       pw_is_subtype((value), PwTypeId_Compound)
 82#define pw_is_exception(value)      pw_is_subtype((value), PwTypeId_Exception)
 83#define pw_is_array(value)          pw_is_subtype((value), PwTypeId_BasicArray)
 84#define pw_is_set(value)            pw_is_subtype((value), PwTypeId_BasicSet)
 85#define pw_is_map(value)            pw_is_subtype((value), PwTypeId_BasicMap)
 86#define pw_is_code(value)           pw_is_subtype((value), PwTypeId_Code)
 87
 88// Integral types
 89typedef nullptr_t  PwType_Null;
 90typedef bool       PwType_Bool;
 91typedef int64_t    PwType_Signed;
 92typedef uint64_t   PwType_Unsigned;
 93typedef double     PwType_Float;
 94
 95PW_UNION(_PwStringParams) {
 96    struct {
 97        uint8_t char_size: 3,
 98                integral:1,
 99                allocated:1,
100                _unused_bits:3;
101    };
102    uint8_t as_byte;
103};
104
105PW_STRUCT(_PwStringData) {
106    // allocated string data for fixed char size strings
107    atomic_uint refcount;
108    uint32_t capacity;  // in characters
109    uint8_t data[];
110};
111
112typedef struct { uint8_t v[3]; } uint24_t;  // three bytes wide characters, always little-endian
113
114PW_STRUCT(_PwStructData) {
115    atomic_uint refcount;
116    atomic_uint itercount;  // XXX not sure atomic is necessary here, using it just for overflow/underflow checking
117                            // performed by _pw_atomic_add/_pw_atomic_sub macros
118};
119
120// forward declarations
121PW_STRUCT(_PwExceptionData);
122PW_STRUCT(PwTask);
123
124// make sure largest C type fits into 64 bits
125static_assert( sizeof(long long) <= sizeof(uint64_t) );
126
127// check UTF-32 char size
128static_assert( sizeof(char32_t) == 4 );
129
130PW_UNION(_PwValue) {
131    /*
132     * 128-bit value
133     */
134
135    uint16_t type_id;
136
137    uint64_t u64[2];
138
139    struct {
140        uint16_t _string_type_id;
141        _PwStringParams str_params;
142    };
143
144    struct {
145        // integral types
146        uint16_t _integral_type_id;
147        uint8_t  carry;  // for integer arithmetic
148        uint8_t  _integral_pagging_1;
149        uint32_t _integral_pagging_2;
150        union {
151            // Integral types
152            PwType_Bool     bool_value;
153            PwType_Signed   signed_value;
154            PwType_Unsigned unsigned_value;
155            PwType_Float    float_value;
156        };
157    };
158
159    struct {
160        // ptr
161        uint16_t _ptr_type_id;
162        uint16_t _ptr_padding_1;
163        uint32_t _ptr_pagging_2;
164        // ISO C forbids conversion of object pointer to function pointer type, so define both
165        union {
166            void* ptr;
167            void (*func_ptr)();
168        };
169    };
170
171    struct {
172        // struct
173        uint16_t _struct_type_id;
174        uint16_t _struct_padding;
175        uint32_t struct_offset;   // data offset for this type id
176        uint8_t* struct_data;     // pointer to the allocated data block
177    };
178
179    struct {
180        // status
181        uint16_t _status_type_id;
182        union {
183            // this field is zero if success and nonzero on error;
184            // for exception it contains PweException code
185            uint16_t status_code;
186            int16_t  pw_errno;
187        };
188        uint32_t kind:2,
189                 line_number:30;
190        const char* file_desc;    // points to __FILE__ which is followed by null character and the description
191    };
192
193    struct {
194        // integral string
195        uint16_t _i_string_type_id;
196        _PwStringParams _i_str_params;
197        uint8_t integral_length;
198        union {
199            uint8_t  str_1[12];
200            uint16_t str_2[6];
201            uint24_t str_3[4];
202            uint32_t str_4[3];
203        };
204    };
205
206    struct {
207        // allocated string
208        uint16_t _a_string_type_id;
209        _PwStringParams _a_str_params;
210        uint8_t _a_padding;
211        uint32_t length;
212        _PwStringData* string_data;
213    };
214
215    struct {
216        // static 0-terminated string
217        uint16_t _s_string_type_id;
218        _PwStringParams _s_str_params;
219        uint8_t  _s_padding;
220        uint32_t _s_length;
221        void* char_ptr;
222    };
223
224    struct {
225        // date/time
226        uint16_t _datetime_type_id;
227        int16_t year;   // negative value may refer to B.C.
228        // -- 32 bits
229        uint8_t month;  // 1-12
230        uint8_t day;    // 1-31
231        uint8_t hour;   // 0-23
232        uint8_t minute; // 0-59
233        // -- 64 bits
234        uint32_t nanosecond;
235        int16_t gmt_offset;  // in minutes
236        uint8_t second; // 0-59
237
238        uint8_t tzindex;
239        /* Index in the zone info cache.
240         * zero for UTC
241         */
242    };
243
244    struct {
245        // timestamp
246        uint16_t _timestamp_type_id;
247        uint16_t ts_userdata;     // for arbitrary use
248        uint32_t ts_nanoseconds;
249        uint64_t ts_seconds;
250    };
251
252    struct {
253        // task and children tasks (special case of task list)
254        uint16_t _task_type_id;
255        uint16_t _task_padding_1;
256        uint32_t _task_padding_2;
257        PwTask* task;
258    };
259};
260
261typedef _PwValue* PwValuePtr;
262
263// make sure _PwValue structure is correct
264static_assert( offsetof(_PwValue, bool_value)  == 8 );
265static_assert( offsetof(_PwValue, ptr)         == 8 );
266static_assert( offsetof(_PwValue, func_ptr)    == 8 );
267static_assert( offsetof(_PwValue, struct_data) == 8 );
268static_assert( offsetof(_PwValue, string_data) == 8 );
269
270static_assert( offsetof(_PwValue, integral_length) == 3 );
271static_assert( offsetof(_PwValue, str_1) == 4 );
272static_assert( offsetof(_PwValue, str_2) == 4 );
273static_assert( offsetof(_PwValue, str_3) == 4 );
274static_assert( offsetof(_PwValue, str_4) == 4 );
275
276static_assert( sizeof(_PwValue) == 16 );
277
278
279/****************************************************************
280 * PwType structure
281 */
282
283PW_STRUCT(PwType) {
284    /*
285     * PW type
286     */
287    uint16_t id;
288    uint16_t num_parents;
289    uint16_t num_base_types;
290    uint16_t num_interface_definitions;  // the number of interfaces provided to pw_add_type
291
292    // Struct type specific data.
293    unsigned data_size;  // size of data for particular mixin
294    unsigned data_alignment;
295    unsigned total_struct_size;  // used to allocate memory for values of this particular type
296                                 // cannot be used in calculations for subtypes
297                                 // because the order of base types can be different in case of multiple inheritance
298
299    uint16_t num_other_interfaces;
300
301    char* name;  // type name
302
303    PwType** parents;     // direct parents
304    PwType** base_types;  // linear list of all ancestors in the order of method resolution
305
306    PwInterface_Generic** interface_definitions;  // interfaces defined for this type, as provided to pw_add_type
307                                                  // i.e. with only id and method functions are set
308    // all interfaces for this type both defined and inherited, with all MRO chains
309    PwInterface_Generic* builtin_interfaces[PW_NUM_BUILTIN_INTERFACES];  // interfaces by id for fast access
310    PwInterface_Generic** other_interfaces;  // lookup table
311
312    Allocator* allocator;  // this applies only to the final type, not for mixins
313
314    /* offsets of all mixin structures that make up the type;
315     * the size equals to the number of base types plus one (self);
316     * the first element is self, the order of other elements is the same as for base_types
317     */
318    unsigned* struct_offsets;
319};
320
321
322void _pw_init_types();
323/*
324 * Initialize types.
325 * Declared with [[gnu::constructor]] attribute and automatically called
326 * before main().
327 *
328 * However, the order of initialization is undefined and other modules
329 * that must call it explicitly from their constructors.
330 *
331 * This function is idempotent.
332 */
333
334extern PwType** _pw_types;
335/*
336 * Global list of types initialized with built-in types.
337 */
338
339#define pw_typeof(value)  (_pw_types[(value)->type_id])
340
341[[nodiscard]] static inline bool _pw_is_subtype_t(PwType* subtype, uint16_t type_id)
342/*
343 * Return true if subtype is really a subtype of type_id.
344 * Caveat: this function does not check if subtype has the same type_id; the caller must do this.
345 */
346{
347    PwType** base_type = subtype->base_types;
348    if (base_type) {
349        PwType** base_types_end = base_type + subtype->num_base_types;
350        while (base_type < base_types_end) {
351            if (type_id == (*base_type)->id) {
352                return true;
353            }
354            base_type++;
355        }
356    }
357    return false;
358}
359
360[[nodiscard]] static inline bool _pw_is_subtype_n(uint16_t subtype_id, uint16_t type_id)
361/*
362 * Return true if subtype_id is really a subtype of type_id.
363 */
364{
365    if (_pw_likely(subtype_id == type_id)) {
366        return true;
367    } else {
368        return _pw_is_subtype_t(_pw_types[subtype_id], type_id);
369    }
370}
371
372[[nodiscard]] static inline bool pw_is_subtype(PwValuePtr value, uint16_t type_id)
373{
374    return _pw_is_subtype_n(value->type_id, type_id);
375}
376
377#define pw_this_data(value)  \
378    ( (void*)( ((uint8_t*) (value)->struct_data) + mthis->struct_offset ) )
379
380void* _pw_get_subtype_struct_ptr(PwValuePtr value, uint16_t type_id);
381
382static inline void* _pw_get_struct_ptr(PwValuePtr value, uint16_t type_id)
383/*
384 * Get pointer to the particular mixin structure of the value.
385 */
386{
387    uint8_t* ptr = value->struct_data;
388    if (_pw_likely(ptr)) {
389        if (_pw_likely(value->type_id == type_id)) {
390            ptr += value->struct_offset;
391        } else {
392            ptr = _pw_get_subtype_struct_ptr(value, type_id);
393        }
394    }
395    return ptr;
396}
397
398[[nodiscard]] bool _pw_iteration_in_progress(PwValuePtr value);
399
400#define pw_iteration_in_progress(value)  \
401    __extension__ \
402    ({  \
403        bool ret = _pw_iteration_in_progress((value));  \
404        if (ret) {  \
405            pw_set_status(PwStatus(PweIterationInProgress));  \
406        }  \
407        ret;  \
408    })
409
410
411#define PW_PARENTS     0x70B5ACE5  // parents delimiter for _pw_add_type
412#define PW_INTERFACES  0x1DEAFACE  // interfaces delimiter for _pw_add_type
413
414[[nodiscard]] uint16_t _pw_add_type(char* name, unsigned data_size, unsigned data_alignment, ...);
415/*
416 * Add type to the first available position in the global list.
417 *
418 * `name` should be a static string.
419 *
420 * Variadic arguments must start from either PW_PARENTS or PW_INTERFACES delimiters.
421 * In case of PW_PARENTS, it must be followed by ids of parent types.
422 * Then goes PW_INTERFACES, followed by pairs of interface id and interface pointer.
423 * The final interface id must be -1 (`pw_add_type` wrappers add this).
424 *
425 * Interfaces override parent methods only if they are not nullptr.
426 * If the type has no parents, all interface methods must be defined.
427 * The only exception is optional methods in the basic interface.
428 *
429 * Return new type id.
430 * Allocator field is initialized with the default one.
431 *
432 * All errors in this function are considered as critical and cause program abort.
433 */
434
435#define pw_add_type(name, ...)  \
436    _pw_add_type((name), 0, 0 __VA_OPT__(,) __VA_ARGS__, -1)
437
438#define pw_add_type2(name, data_type, ...)  \
439    _pw_add_type((name), sizeof(data_type), alignof(data_type) __VA_OPT__(,) __VA_ARGS__, -1)
440
441#define pw_get_type_name(v) _Generic((v),        \
442                  char: _pw_get_type_name_by_id, \
443         unsigned char: _pw_get_type_name_by_id, \
444                 short: _pw_get_type_name_by_id, \
445        unsigned short: _pw_get_type_name_by_id, \
446                   int: _pw_get_type_name_by_id, \
447          unsigned int: _pw_get_type_name_by_id, \
448                  long: _pw_get_type_name_by_id, \
449         unsigned long: _pw_get_type_name_by_id, \
450             long long: _pw_get_type_name_by_id, \
451    unsigned long long: _pw_get_type_name_by_id, \
452            PwValuePtr: _pw_get_type_name_from_value  \
453    )(v)
454
455[[nodiscard]] static inline char* _pw_get_type_name_by_id     (uint16_t type_id) { return _pw_types[type_id]->name; }
456[[nodiscard]] static inline char* _pw_get_type_name_from_value(PwValuePtr value) { return _pw_types[value->type_id]->name; }
457
458void pw_dump_types(FILE* fp);
459
460
461/****************************************************************
462 * Initializers and rvalues
463 */
464
465#define PW_NULL {.type_id = PwTypeId_Null}
466
467#define PwNull()  \
468    /* make Bool rvalue */  \
469    __extension__ \
470    ({  \
471        _PwValue __v = PW_NULL;  \
472        __v;  \
473    })
474
475#define PW_BOOL(initializer)  \
476    {  \
477        ._integral_type_id = PwTypeId_Bool,  \
478        .bool_value = (initializer)  \
479    }
480
481#define PwBool(initializer)  \
482    /* make Bool rvalue */  \
483    __extension__ \
484    ({  \
485        _PwValue __v = PW_BOOL(initializer);  \
486        __v;  \
487    })
488
489#define PW_SIGNED(initializer)  \
490    {  \
491        ._integral_type_id = PwTypeId_Signed,  \
492        .signed_value = (initializer),  \
493    }
494
495#define PwSigned(initializer)  \
496    /* make Signed rvalue */  \
497    __extension__ \
498    ({  \
499        _PwValue __v = PW_SIGNED(initializer);  \
500        __v;  \
501    })
502
503#define PW_UNSIGNED(initializer)  \
504    {  \
505        ._integral_type_id = PwTypeId_Unsigned,  \
506        .unsigned_value = (initializer)  \
507    }
508
509#define PwUnsigned(initializer)  \
510    /* make Unsigned rvalue */  \
511    __extension__ \
512    ({  \
513        _PwValue __v = PW_UNSIGNED(initializer);  \
514        __v;  \
515    })
516
517#define PW_FLOAT(initializer)  \
518    {  \
519        ._integral_type_id = PwTypeId_Float,  \
520        .float_value = (initializer)  \
521    }
522
523#define PwFloat(initializer)  \
524    /* make Float rvalue */  \
525    __extension__ \
526    ({  \
527        _PwValue __v = PW_FLOAT(initializer);  \
528        __v;  \
529    })
530
531#define PW_STRING(...)  \
532    /* Integral string, character size 1 byte, up to 12 chars; initializer is optional */  \
533    {  \
534        ._i_string_type_id = PwTypeId_String,  \
535        ._i_str_params = {  \
536            .integral = 1,  \
537            .char_size = 1  \
538        }  \
539        __VA_OPT__( ,  \
540            .integral_length = sizeof(__VA_ARGS__ "\0") - 2,  \
541            .str_1 = __VA_ARGS__  \
542        )  \
543    }
544
545#define PwString(...)  \
546    /* make String rvalue, character size 1 byte, up to 12 chars; initializer is optional */  \
547    __extension__ \
548    ({  \
549        _PwValue __s = PW_STRING(__VA_ARGS__);  \
550        __s;  \
551    })
552
553#define PW_STRING_UTF32(...)  \
554    /* Integral string, character size 4 bytes, up to 3 chars; initializer is optional */  \
555    {  \
556        ._i_string_type_id = PwTypeId_String,  \
557        ._i_str_params = {  \
558            .integral = 1,  \
559            .char_size = 4  \
560        }  \
561        __VA_OPT__( ,  \
562            .integral_length = (sizeof(__VA_ARGS__ "\0") / 4) - 2,  \
563            .str_4 = __VA_ARGS__  \
564        )  \
565    }
566
567#define PwStringUtf32(...)  \
568    /* make String rvalue, character size 4 bytes, up to 3 chars; initializer is optional */  \
569    __extension__ \
570    ({  \
571        _PwValue __s = PW_STRING_UTF32(__VA_ARGS__);  \
572        __s;  \
573    })
574
575#define PW_STATIC_STRING(initializer)  \
576    /* Static string, character size 1 byte */  \
577    {  \
578        ._s_string_type_id = PwTypeId_String,  \
579        ._s_str_params = {  \
580            .char_size = 1  \
581        },  \
582        ._s_length = sizeof(initializer "\0") - 2,  \
583        .char_ptr = initializer  \
584    }
585
586#define PwStaticString(initializer)  \
587    /* make static String rvalue, character size 1 byte */  \
588    __extension__ \
589    ({  \
590        _PwValue __s = {  \
591            ._s_string_type_id = PwTypeId_String,  \
592            ._s_str_params = {  \
593                .char_size = 1  \
594            },  \
595            .char_ptr = initializer  \
596        };  \
597        __s.length = strlen(initializer);  \
598        __s;  \
599    })
600
601#define PW_STATIC_STRING_UTF32(initializer)  \
602    /* Static UTF-32 string */  \
603    {  \
604        ._s_string_type_id = PwTypeId_String,  \
605        ._s_str_params = {  \
606            .char_size = 4  \
607        },  \
608        ._s_length = (sizeof(initializer "\0") / 4) - 2,  \
609        .char_ptr = initializer  \
610    }
611
612#define PwStaticStringUtf32(initializer)  \
613    /* make static String rvalue, character size 4 bytes */  \
614    __extension__ \
615    ({  \
616        _PwValue __s = {  \
617            ._s_string_type_id = PwTypeId_String,  \
618            ._s_str_params = {  \
619                .char_size = 4  \
620            },  \
621            .char_ptr = initializer  \
622        };  \
623        __s.length = utf32_strlen(initializer);  \
624        __s;  \
625    })
626
627#define PW_DATETIME(_year, _month, _day, _hour, _minute, _second)  \
628    {  \
629        ._datetime_type_id = PwTypeId_DateTime,  \
630        .year   = _year,  \
631        .month  = _month,  \
632        .day    = _day,  \
633        .hour   = _hour,  \
634        .minute = _minute,  \
635        .second = _second  \
636    }
637
638#define PwDateTime(_year, _month, _day, _hour, _minute, _second)  \
639    /* make DateTime rvalue */  \
640    __extension__ \
641    ({  \
642        _PwValue __v = PW_DATETIME(_year, _month, _day, _hour, _minute, _second);  \
643        __v;  \
644    })
645
646#define PW_TIMESTAMP(seconds, nanoseconds)  \
647    {  \
648        ._timestamp_type_id = PwTypeId_Timestamp,  \
649        .ts_seconds = (seconds),  \
650        .ts_nanoseconds = (nanoseconds),  \
651    }
652
653#define PwTimestamp(seconds, nanoseconds)  \
654    /* make Timestamp rvalue */  \
655    __extension__ \
656    ({  \
657        _PwValue __v = PW_TIMESTAMP((seconds), (nanoseconds));  \
658        __v;  \
659    })
660
661#define PW_PTR(initializer)  \
662    {  \
663        ._ptr_type_id = PwTypeId_Ptr,  \
664        .ptr = (initializer)  \
665    }
666
667#define PwPtr(initializer)  \
668    /* make Ptr rvalue */  \
669    __extension__ \
670    ({  \
671        _PwValue __v = PW_PTR(initializer);  \
672        __v;  \
673    })
674
675#define PwVaEnd()  \
676    /* make VA_END rvalue */  \
677    __extension__ \
678    ({  \
679        _PwValue __status = {  \
680            ._status_type_id = PwTypeId_Status,  \
681            .kind = PwStatusKind_VA_END  \
682        };  \
683        __status;  \
684    })
685
686#define PW_SUCCESS  \
687    {  \
688        ._status_type_id = PwTypeId_Status  \
689    }
690
691#define PwSuccess()  \
692    __extension__ \
693    ({  \
694        _PwValue __status = PW_SUCCESS;  \
695        __status;  \
696    })
697
698#define _PW_STATUS_INITIALIZER(_kind, _code, ...)  \
699    {  \
700        ._status_type_id = PwTypeId_Status,  \
701        .kind = (_kind),  \
702        .status_code = (_code),  \
703        .line_number = __LINE__,  \
704        .file_desc = __FILE__ "\0" __VA_ARGS__ "\0"  \
705    }
706
707#define PW_STATUS(_code, ...)  \
708    _PW_STATUS_INITIALIZER(PwStatusKind_Basic, (_code) __VA_OPT__(,) __VA_ARGS__)
709
710
711#define PwStatus(_code, ...)  \
712    /* make Status rvalue */  \
713    __extension__ \
714    ({  \
715        _PwValue __status = PW_STATUS((_code) __VA_OPT__(,) __VA_ARGS__);  \
716        __status;  \
717    })
718
719#define PwErrno(_errno, ...)  \
720    /* make Status rvalue */  \
721    __extension__ \
722    ({  \
723        _PwValue __status = _PW_STATUS_INITIALIZER(PwStatusKind_Errno, (_errno) __VA_OPT__(,) __VA_ARGS__);  \
724        __status;  \
725    })
726
727#define PwOOM(...)  \
728    PwErrno(ENOMEM __VA_OPT__(,) __VA_ARGS__)
729
730
731/****************************************************************
732 * API for compound types
733 */
734
735PW_STRUCT(_PwCompoundChain) {
736    /*
737     * Compound values may contain cyclic references.
738     * This structure along with function `_pw_on_chain`
739     * helps to detect them.
740     * See dump implementation for array and map values.
741     */
742    _PwCompoundChain* prev;
743    PwValuePtr value;
744};
745
746void _pw_compound_join(PwValuePtr parent, PwValuePtr child);
747/*
748 * If `child` is a compound value, join it with `parent`.
749 */
750
751void _pw_compound_split(PwValuePtr parent, PwValuePtr child);
752/*
753 * If `child` is a compound value, split it from `parent`.
754 * This function may destroy `child` if the last reference to it is held py `parent`.
755 */
756
757[[nodiscard]] PwValuePtr _pw_value_is_on_chain(PwValuePtr value, _PwCompoundChain* tail);
758
759[[nodiscard]] static inline PwValuePtr _pw_on_chain(PwValuePtr value, _PwCompoundChain* tail)
760/*
761 * Check if value struct_data is on chain.
762 */
763{
764    if (_pw_unlikely(tail)) {
765        return _pw_value_is_on_chain(value, tail);
766    } else {
767        return nullptr;
768    }
769}
770
771
772/****************************************************************
773 * Destructor
774 */
775
776void pw_destroy_compound(PwValuePtr value, _PwCompoundChain* tail);
777/*
778 * Destroy value: call destructor (if refcount drops to zero for refcounted values) and make `value` Null.
779 */
780
781static inline void pw_destroy(PwValuePtr value)
782{
783    if (_pw_likely(value->type_id < PW_NUM_INTEGRAL_TYPES
784        || (value->type_id == PwTypeId_String && !value->str_params.allocated))) {
785        *value = PwNull();
786        return;
787    }
788    pw_destroy_compound(value, nullptr);
789}
790
791
792/****************************************************************
793 * Move
794 */
795
796static inline void pw_move(PwValuePtr result, PwValuePtr v)
797/*
798 * "Move" value to another variable or out of the function
799 * (i.e. return a value and reset autocleaned variable)
800 * `result` is destroyed before moving.
801 */
802{
803    pw_destroy(result);
804    *result = *v;
805    *v = PwNull();
806}
807
808#ifdef __cplusplus
809}
810#endif