Skip to content

StrIterIndex

Description

Absolute cursor index within the StrIter’s backing region. Alias- reframe of IterIndex in string vocabulary. See IterIndex for the full contract.

Parameters

Name Direction Description
mi in Pointer to the StrIter to query.

Success

Returns the absolute cursor index within the backing region.

Failure

Macro cannot fail.

Usage example (Cross-references)

Usage examples (Cross-references)
                                                                                                                           \
                /* if no advancement in read position */                                                                   \
                if (StrIterIndex(&UNPL(si_before_read)) == StrIterIndex(&si)) {                                            \
                    /* skip the value */                                                                                   \
                    StrIter UNPL(read_si) = JSkipValue(si);                                                                \
                                                                                                                           \
                    /* if still no advancement in read position */                                                         \
                    if (StrIterIndex(&UNPL(read_si)) == StrIterIndex(&si)) {                                               \
                        LOG_ERROR("Failed to parse value. Invalid JSON.");                                                 \
                        UNPL(failed) = true;                                                                               \
                /* key start */                                                                                            \
                UNPL(read_si) = JReadString(si, &key);                                                                     \
                if (StrIterIndex(&UNPL(read_si)) == StrIterIndex(&si)) {                                                   \
                    LOG_ERROR("Failed to read string key in object. Invalid JSON");                                        \
                    StrDeinit(&key);                                                                                       \
                                                                                                                           \
                /* if no advancement in read position */                                                                   \
                if (StrIterIndex(&UNPL(si_before_read)) == StrIterIndex(&si)) {                                            \
                    /* skip the value */                                                                                   \
                    UNPL(read_si) = JSkipValue(si);                                                                        \
                                                                                                                           \
                    /* if still no advancement in read position */                                                         \
                    if (StrIterIndex(&UNPL(read_si)) == StrIterIndex(&si)) {                                               \
                        LOG_ERROR("Failed to parse value. Invalid JSON.");                                                 \
                        StrDeinit(&key);                                                                                   \
            LOG_ERROR("Failed to parse f64: empty input");
            DefaultAllocatorDeinit(&scratch);
            return StrIterDataAt(&si, StrIterIndex(&si));
        }
        if ((c == 'i' || c == 'I' || c == 'n' || c == 'N') || (c == '-' && (c1 == 'i' || c1 == 'I'))) {
            StrIter saved = si;
            Zstr    start = StrIterDataAt(&si, StrIterIndex(&si));
            while (StrIterPeek(&si, &c) && !IS_SPACE(c)) {
                StrIterMustNext(&si);
            }
    
            Str temp = StrInitFromCstr(start, (size)(StrIterIndex(&si) - StrIterIndex(&saved)), &scratch);
    
            // Special-value tokens (`inf`, `nan`, ...) carry through the
                StrDeinit(&temp);
                DefaultAllocatorDeinit(&scratch);
                return StrIterDataAt(&si, StrIterIndex(&si));
            }
            StrDeinit(&temp);
            // least one digit, otherwise rewind so the 'e' is left to the
            // caller's tail (e.g. a unit suffix).
            if ((c == 'e' || c == 'E') && StrIterIndex(&si) > StrIterIndex(&saved)) {
                StrIterMustNext(&si);
            }
    
            if (!is_valid_number_char(c, StrIterIndex(&si) == StrIterIndex(&saved), true)) {
                break;
            }
        }
    
        Zstr start = StrIterDataAt(&si, StrIterIndex(&saved));
        size pos   = StrIterIndex(&si) - StrIterIndex(&saved);
    
        Zstr start = StrIterDataAt(&si, StrIterIndex(&saved));
        size pos   = StrIterIndex(&si) - StrIterIndex(&saved);
    
        Str temp = StrInitFromCstr(start, pos, &scratch);
            LOG_ERROR("Failed to parse u8: empty input");
            DefaultAllocatorDeinit(&scratch);
            return StrIterDataAt(&si, StrIterIndex(&si));
        }
    
        if (fmt_info && (fmt_info->flags & FMT_FLAG_CHAR)) {
            Zstr next = read_chars_internal(StrIterDataAt(&si, StrIterIndex(&si)), (u8 *)v, sizeof(*v), fmt_info);
            DefaultAllocatorDeinit(&scratch);
            return next;
    
        while (StrIterPeek(&si, &c)) {
            if (!is_valid_number_char(c, StrIterIndex(&si) == StrIterIndex(&saved), false)) {
                break;
            }
        }
    
        Zstr start = StrIterDataAt(&si, StrIterIndex(&saved));
        size pos   = StrIterIndex(&si) - StrIterIndex(&saved);
    
        Zstr start = StrIterDataAt(&si, StrIterIndex(&saved));
        size pos   = StrIterIndex(&si) - StrIterIndex(&saved);
    
        Str temp = StrInitFromCstr(start, pos, &scratch);
                LOG_ERROR("Failed to parse " #NAME ": empty input");                                                       \
                DefaultAllocatorDeinit(&scratch);                                                                          \
                return StrIterDataAt(&si, StrIterIndex(&si));                                                              \
            }                                                                                                              \
                                                                                                                           \
            StrIter saved = si;                                                                                            \
            while (StrIterPeek(&si, &c)) {                                                                                 \
                if (!is_valid_number_char(c, StrIterIndex(&si) == StrIterIndex(&saved), false)) {                          \
                    break;                                                                                                 \
                }                                                                                                          \
            }                                                                                                              \
                                                                                                                           \
            Zstr start = StrIterDataAt(&si, StrIterIndex(&saved));                                                         \
            size pos   = StrIterIndex(&si) - StrIterIndex(&saved);                                                         \
            Str  temp  = StrInitFromCstr(start, pos, &scratch);                                                            \
                                                                                                                           \
            Zstr start = StrIterDataAt(&si, StrIterIndex(&saved));                                                         \
            size pos   = StrIterIndex(&si) - StrIterIndex(&saved);                                                         \
            Str  temp  = StrInitFromCstr(start, pos, &scratch);                                                            \
                                                                                                                           \
        if (!StrIterRemainingLength(&si)) {
            LOG_ERROR("Empty input string");
            return StrIterDataAt(&si, StrIterIndex(&si));
        }
        }
    
        Zstr start = StrIterDataAt(&si, StrIterIndex(&si));
    
        char c0 = 0;
            }
    
            if (StrIterIndex(&si) == StrIterIndex(&hex_saved)) {
                LOG_ERROR("Invalid hex format - no digits after 0x");
                return start;
    
            Str hex_str = StrInitFromCstr(
                StrIterDataAt(&si, StrIterIndex(&hex_saved)),
                StrIterIndex(&si) - StrIterIndex(&hex_saved),
                BitVecAllocator(bv)
            Str hex_str = StrInitFromCstr(
                StrIterDataAt(&si, StrIterIndex(&hex_saved)),
                StrIterIndex(&si) - StrIterIndex(&hex_saved),
                BitVecAllocator(bv)
            );
            *bv = BitVecFromInteger(value, bit_len, BitVecAllocator(bv));
            StrDeinit(&hex_str);
            return StrIterDataAt(&si, StrIterIndex(&si));
        }
            }
    
            if (StrIterIndex(&si) == StrIterIndex(&oct_saved)) {
                LOG_ERROR("Invalid octal format - no digits after 0o");
                return start;
    
            Str oct_str = StrInitFromCstr(
                StrIterDataAt(&si, StrIterIndex(&oct_saved)),
                StrIterIndex(&si) - StrIterIndex(&oct_saved),
                BitVecAllocator(bv)
            Str oct_str = StrInitFromCstr(
                StrIterDataAt(&si, StrIterIndex(&oct_saved)),
                StrIterIndex(&si) - StrIterIndex(&oct_saved),
                BitVecAllocator(bv)
            );
            *bv = BitVecFromInteger(value, bit_len, BitVecAllocator(bv));
            StrDeinit(&oct_str);
            return StrIterDataAt(&si, StrIterIndex(&si));
        }
        }
    
        if (StrIterIndex(&si) == StrIterIndex(&bin_saved)) {
            LOG_ERROR("Invalid binary format - expected 0s and 1s");
            return start;
    
        Str bin_str = StrInitFromCstr(
            StrIterDataAt(&si, StrIterIndex(&bin_saved)),
            StrIterIndex(&si) - StrIterIndex(&bin_saved),
            BitVecAllocator(bv)
        Str bin_str = StrInitFromCstr(
            StrIterDataAt(&si, StrIterIndex(&bin_saved)),
            StrIterIndex(&si) - StrIterIndex(&bin_saved),
            BitVecAllocator(bv)
        );
    
        StrDeinit(&bin_str);
        return StrIterDataAt(&si, StrIterIndex(&si));
    }
    #endif // FEATURE_BITVEC
        if (!StrIterRemainingLength(&si)) {
            LOG_ERROR("Failed to parse Int: empty input");
            return StrIterDataAt(&si, StrIterIndex(&si));
        }
        StrIter saved        = si;
        StrIter digits_saved = si;
        Zstr    start        = StrIterDataAt(&si, StrIterIndex(&saved));
        u8      radix        = int_fmt_radix_from_flags(fmt_info);
        }
    
        if (StrIterIndex(&si) == StrIterIndex(&digits_saved)) {
            LOG_ERROR("Failed to parse Int");
            return start;
        }
    
        Str  temp   = StrInitFromCstr(start, StrIterIndex(&si) - StrIterIndex(&saved), IntAllocator(value));
        Int  parsed = IntInit(IntAllocator(value));
        bool ok     = IntTryFromStrRadix(&parsed, StrBegin(&temp), radix);
    
        StrDeinit(&temp);
        return StrIterDataAt(&si, StrIterIndex(&si));
    }
    #endif // FEATURE_INT
            StrDeinit(&temp);
            FloatDeinit(&parsed);
            return StrIterDataAt(&si, StrIterIndex(&si));
        }
        }
    
        start     = StrIterDataAt(&si, StrIterIndex(&si));
        token_len = float_fmt_token_length(start);
            LOG_ERROR("Failed to parse f32: empty input");
            DefaultAllocatorDeinit(&scratch);
            return StrIterDataAt(&si, StrIterIndex(&si));
        }
        if ((c == 'i' || c == 'I' || c == 'n' || c == 'N') || (c == '-' && (c1 == 'i' || c1 == 'I'))) {
            StrIter saved = si;
            Zstr    start = StrIterDataAt(&si, StrIterIndex(&si));
            while (StrIterPeek(&si, &c) && !IS_SPACE(c)) {
                StrIterMustNext(&si);
            }
    
            Str temp = StrInitFromCstr(start, (size)(StrIterIndex(&si) - StrIterIndex(&saved)), &scratch);
    
            // Special-value tokens (`inf`, `nan`, ...) carry through the
                StrDeinit(&temp);
                DefaultAllocatorDeinit(&scratch);
                return StrIterDataAt(&si, StrIterIndex(&si));
            }
            StrDeinit(&temp);
            // least one digit, otherwise rewind so the 'e' is left to the
            // caller's tail.
            if ((c == 'e' || c == 'E') && StrIterIndex(&si) > StrIterIndex(&saved)) {
                StrIterMustNext(&si);
            }
    
            if (!is_valid_number_char(c, StrIterIndex(&si) == StrIterIndex(&saved), true)) {
                break;
            }
        }
    
        Zstr start = StrIterDataAt(&si, StrIterIndex(&saved));
        size pos   = StrIterIndex(&si) - StrIterIndex(&saved);
    
        Zstr start = StrIterDataAt(&si, StrIterIndex(&saved));
        size pos   = StrIterIndex(&si) - StrIterIndex(&saved);
    
        Str temp = StrInitFromCstr(start, pos, &scratch);
    
            // First token: IP literal.
            size ip_start = StrIterIndex(&si);
            while (StrIterPeek(&si, &c) && !is_hspace(c) && c != '\n') {
                StrIterMustNext(&si);
                StrIterMustNext(&si);
            }
            u64 ip_len = (u64)(StrIterIndex(&si) - ip_start);
    
            bool got_v4 = false;
                    break;
                }
                size nm_start = StrIterIndex(&si);
                while (StrIterPeek(&si, &c) && !is_hspace(c) && c != '\n' && c != '#') {
                    StrIterMustNext(&si);
                    StrIterMustNext(&si);
                }
                u64 nm_len = (u64)(StrIterIndex(&si) - nm_start);
                if (nm_len == 0) {
                    break;
            char sep;
            if (StrIterRemainingLength(&si) > kw_len &&
                MemCompare(StrIterDataAt(&si, StrIterIndex(&si)), NS_KEYWORD, kw_len) == 0 &&
                StrIterPeekAt(&si, (i64)kw_len, &sep) && (sep == ' ' || sep == '\t')) {
                StrIterMustMove(&si, (i64)kw_len);
                skip_hspace_iter(&si);
    
                size ip_start = StrIterIndex(&si);
                while (StrIterPeek(&si, &c) && !is_hspace(c) && c != '\n' && c != '#') {
                    StrIterMustNext(&si);
                    StrIterMustNext(&si);
                }
                u64 ip_len = (u64)(StrIterIndex(&si) - ip_start);
                if (ip_len > 0 && ip_len < 64) {
                    StrInitStack(ip_buf, 64) {
        while (StrIterPeek(&si, &c)) {
            // Find next dot or end-of-string.
            size seg_start = StrIterIndex(&si);
            while (StrIterPeek(&si, &c) && c != '.') {
                StrIterMustNext(&si);
                StrIterMustNext(&si);
            }
            u64 seg_len = (u64)(StrIterIndex(&si) - seg_start);
            if (seg_len == 0) {
                // Trailing dot at the end is valid (means root); leading or
    
        si = KvConfigReadKey(si, key);
        if (StrIterIndex(&si) == StrIterIndex(&saved_si)) {
            return saved_si;
        }
        si = KvConfigReadValue(si, value);
    
        if (StrIterIndex(&si) == StrIterIndex(&saved_si)) {
            StrClear(key);
            StrClear(value);
    
            read_si = KvConfigReadPair(si, &key, &value);
            if (StrIterIndex(&read_si) == StrIterIndex(&si)) {
                StrDeinit(&key);
                StrDeinit(&value);
        // with \0 in place so the path is a usable C string aliasing the
        // iter's backing buffer.
        size path_start_pos = StrIterIndex(si);
        char c;
        while (StrIterPeek(si, &c) && c != '\n') {
            StrIterMustNext(si);
        }
        size line_terminator_pos = StrIterIndex(si);
    
        out->start       = start;
            // key start
            read_si = JReadString(si, &key);
            if (StrIterIndex(&read_si) == StrIterIndex(&si)) {
                LOG_ERROR("Failed to read string key in object. Invalid JSON");
                StrDeinit(&key);
    
            // if still no advancement in read position
            if (StrIterIndex(&read_si) == StrIterIndex(&si)) {
                LOG_ERROR("Failed to parse value. Invalid JSON.");
                StrDeinit(&key);
    
            // if no advancement in read position
            if (StrIterIndex(&read_si) == StrIterIndex(&si)) {
                LOG_ERROR("Failed to parse value. Invalid JSON.");
                return saved_si;
    
        if (!StrLen(&ns)) {
            LOG_ERROR("Failed to parse number. '{.8}'", LVAL(StrIterDataAt(&saved_si, StrIterIndex(&saved_si))));
            StrDeinit(&ns);
            DefaultAllocatorDeinit(&scratch);
        si = JReadNumber(si, &num);
    
        if (StrIterIndex(&si) == StrIterIndex(&saved_si)) {
            LOG_ERROR("Failed to parse integer number.");
            return saved_si;
        si = JReadNumber(si, &num);
    
        if (StrIterIndex(&si) == StrIterIndex(&saved_si)) {
            LOG_ERROR("Failed to parse floating point number");
            return saved_si;
            si = JReadBool(si, &b);
    
            if (StrIterIndex(&si) == StrIterIndex(&before_si)) {
                LOG_ERROR(
                    "Failed to read boolean value. Expected true/false. Invalid "
            si = JReadNull(si, &n);
    
            if (StrIterIndex(&si) == StrIterIndex(&before_si)) {
                LOG_ERROR(
                    "Failed to read boolean value. Expected true/false. Invalid "
            DefaultAllocatorDeinit(&scratch);
    
            if (StrIterIndex(&si) == StrIterIndex(&before_si)) {
                LOG_ERROR("Failed to read string value. Expected string. Invalid JSON.");
                return saved_si;
            si = JReadNumber(si, &num);
    
            if (StrIterIndex(&si) == StrIterIndex(&before_si)) {
                LOG_ERROR("Failed to read number value. Expected a number. Invalid JSON.");
                return saved_si;
            si                = JSkipObject(si);
    
            if (StrIterIndex(&si) == StrIterIndex(&before_si)) {
                LOG_ERROR("Failed to read object. Expected an object. Invalid JSON.");
                return saved_si;
            si                = JSkipArray(si);
    
            if (StrIterIndex(&si) == StrIterIndex(&before_si)) {
                LOG_ERROR("Failed to read array. Expected an array. Invalid JSON.");
                return saved_si;
            return false;
        }
        return StrIterIndex(&si) == 0;
    }
            return false;
        }
        return StrIterIndex(&si) == 0;
    }
            return false;
        }
        return StrIterIndex(&si) == 1;
    }
            return false;
        }
        return StrIterIndex(&si) == 0;
    }
                Str key       = StrInit(&alloc);                                                                           \
                UNPL(read_si) = JReadString(si, &key);                                                                     \
                if (StrIterIndex(&UNPL(read_si)) == StrIterIndex(&si)) {                                                   \
                    LOG_ERROR("Failed to read string key in object. Invalid JSON");                                        \
                    StrDeinit(&key);                                                                                       \
                StrIter UNPL(si_before_read) = si;                                                                         \
                { reader }                                                                                                 \
                if (StrIterIndex(&UNPL(si_before_read)) == StrIterIndex(&si)) {                                            \
                    StrIter UNPL(skip_si) = JSkipValue(si);                                                                \
                    if (StrIterIndex(&UNPL(skip_si)) == StrIterIndex(&si)) {                                               \
                if (StrIterIndex(&UNPL(si_before_read)) == StrIterIndex(&si)) {                                            \
                    StrIter UNPL(skip_si) = JSkipValue(si);                                                                \
                    if (StrIterIndex(&UNPL(skip_si)) == StrIterIndex(&si)) {                                               \
                        LOG_ERROR("Failed to parse value. Invalid JSON.");                                                 \
                        StrDeinit(&key);                                                                                   \
            bool    b   = true;
            StrIter out = JReadBool(si, &b);
            if (StrIterIndex(&out) != StrIterIndex(&si)) {
                WriteFmtLn("[DEBUG] JReadBool advanced on malformed 'tru3'");
                success = false;
            bool    b   = true;
            StrIter out = JReadBool(si, &b);
            if (StrIterIndex(&out) != StrIterIndex(&si)) {
                WriteFmtLn("[DEBUG] JReadBool advanced on malformed 'fXlse'");
                success = false;
            bool    b   = true;
            StrIter out = JReadBool(si, &b);
            if (StrIterIndex(&out) != StrIterIndex(&si)) {
                WriteFmtLn("[DEBUG] JReadBool advanced on too-short 'tr'");
                success = false;
            bool    is_null = true;
            StrIter out     = JReadNull(si, &is_null);
            if (StrIterIndex(&out) != StrIterIndex(&si)) {
                WriteFmtLn("[DEBUG] JReadNull advanced on malformed 'nuXX'");
                success = false;
            StrIter out = JReadBool(si, &b);
            // value correct and exactly 4 bytes consumed
            if (!(b == true && StrIterIndex(&out) == 4)) {
                WriteFmtLn("[DEBUG] JReadBool 'true' value/advance wrong: b={}, idx={}", b, StrIterIndex(&out));
                success = false;
            // value correct and exactly 4 bytes consumed
            if (!(b == true && StrIterIndex(&out) == 4)) {
                WriteFmtLn("[DEBUG] JReadBool 'true' value/advance wrong: b={}, idx={}", b, StrIterIndex(&out));
                success = false;
            }
            bool    b   = true;
            StrIter out = JReadBool(si, &b);
            if (!(b == false && StrIterIndex(&out) == 5)) {
                WriteFmtLn("[DEBUG] JReadBool 'false' value/advance wrong: b={}, idx={}", b, StrIterIndex(&out));
                success = false;
            StrIter out = JReadBool(si, &b);
            if (!(b == false && StrIterIndex(&out) == 5)) {
                WriteFmtLn("[DEBUG] JReadBool 'false' value/advance wrong: b={}, idx={}", b, StrIterIndex(&out));
                success = false;
            }
            bool    is_null = false;
            StrIter out     = JReadNull(si, &is_null);
            if (!(is_null == true && StrIterIndex(&out) == 4)) {
                WriteFmtLn("[DEBUG] JReadNull 'null' value/advance wrong: n={}, idx={}", is_null, StrIterIndex(&out));
                success = false;
            StrIter out     = JReadNull(si, &is_null);
            if (!(is_null == true && StrIterIndex(&out) == 4)) {
                WriteFmtLn("[DEBUG] JReadNull 'null' value/advance wrong: n={}, idx={}", is_null, StrIterIndex(&out));
                success = false;
            }
            bool    b   = false;
            StrIter out = JReadBool(si, &b);
            if (!(b == true && StrIterIndex(&out) == 4)) {
                WriteFmtLn("[DEBUG] JReadBool exact 'true' wrong: b={}, idx={}", b, StrIterIndex(&out));
                success = false;
            StrIter out = JReadBool(si, &b);
            if (!(b == true && StrIterIndex(&out) == 4)) {
                WriteFmtLn("[DEBUG] JReadBool exact 'true' wrong: b={}, idx={}", b, StrIterIndex(&out));
                success = false;
            }
            bool    b   = true;
            StrIter out = JReadBool(si, &b);
            if (!(b == false && StrIterIndex(&out) == 5)) {
                WriteFmtLn("[DEBUG] JReadBool exact 'false' wrong: b={}, idx={}", b, StrIterIndex(&out));
                success = false;
            StrIter out = JReadBool(si, &b);
            if (!(b == false && StrIterIndex(&out) == 5)) {
                WriteFmtLn("[DEBUG] JReadBool exact 'false' wrong: b={}, idx={}", b, StrIterIndex(&out));
                success = false;
            }
            bool    is_null = false;
            StrIter out     = JReadNull(si, &is_null);
            if (!(is_null == true && StrIterIndex(&out) == 4)) {
                WriteFmtLn("[DEBUG] JReadNull exact 'null' wrong: n={}, idx={}", is_null, StrIterIndex(&out));
                success = false;
            StrIter out     = JReadNull(si, &is_null);
            if (!(is_null == true && StrIterIndex(&out) == 4)) {
                WriteFmtLn("[DEBUG] JReadNull exact 'null' wrong: n={}, idx={}", is_null, StrIterIndex(&out));
                success = false;
            }
            StrIter r   = JReadString(si, &out);
            // Truncated escape -> failure -> iterator unchanged.
            if (StrIterIndex(&r) != StrIterIndex(&si)) {
                WriteFmtLn("[DEBUG] JReadString advanced on truncated escape case {}", i);
                success = false;
            Str     out = StrInit(&alloc);
            StrIter r   = JReadString(si, &out);
            if (StrIterIndex(&r) != StrIterIndex(&si)) {
                WriteFmtLn("[DEBUG] JReadString accepted a complete \\u escape (should reject): idx={}", StrIterIndex(&r));
                success = false;
            StrIter r   = JReadString(si, &out);
            if (StrIterIndex(&r) != StrIterIndex(&si)) {
                WriteFmtLn("[DEBUG] JReadString accepted a complete \\u escape (should reject): idx={}", StrIterIndex(&r));
                success = false;
            }
            Str     out = StrInit(&alloc);
            StrIter r   = JReadString(si, &out);
            if (StrIterIndex(&r) == StrIterIndex(&si) || StrIterIndex(&r) != StrIterLength(&r)) {
                WriteFmtLn("[DEBUG] JReadString failed on a plain string: idx={}", StrIterIndex(&r));
                success = false;
            StrIter r   = JReadString(si, &out);
            if (StrIterIndex(&r) == StrIterIndex(&si) || StrIterIndex(&r) != StrIterLength(&r)) {
                WriteFmtLn("[DEBUG] JReadString failed on a plain string: idx={}", StrIterIndex(&r));
                success = false;
            }
            success = false;
        }
        if (StrIterIndex(&si) != StrIterLength(&si)) {
            WriteFmtLn(
                "[DEBUG] iterator did not consume whole object: idx={}, len={}",
            WriteFmtLn(
                "[DEBUG] iterator did not consume whole object: idx={}, len={}",
                StrIterIndex(&si),
                StrIterLength(&si)
            );
    
            // On structural failure the macro restores si to its start.
            if (StrIterIndex(&si) != 0) {
                WriteFmtLn("[DEBUG] malformed object case {} did not rewind: idx={}", i, StrIterIndex(&si));
                success = false;
            // On structural failure the macro restores si to its start.
            if (StrIterIndex(&si) != 0) {
                WriteFmtLn("[DEBUG] malformed object case {} did not rewind: idx={}", i, StrIterIndex(&si));
                success = false;
            }
            i64     v   = 0;
            StrIter out = JReadInteger(si, &v);
            if (!(StrIterIndex(&out) != StrIterIndex(&si) && v == -12345)) {
                WriteFmtLn("[DEBUG] JReadInteger '-12345' -> {}", v);
                success = false;
            i64     v   = 0;
            StrIter out = JReadInteger(si, &v);
            if (!(StrIterIndex(&out) != StrIterIndex(&si) && v == 12345)) {
                WriteFmtLn("[DEBUG] JReadInteger '12345' -> {}", v);
                success = false;
            f64     v   = 0.0;
            StrIter out = JReadFloat(si, &v);
            if (!(StrIterIndex(&out) != StrIterIndex(&si) && v == -2.5)) {
                WriteFmtLn("[DEBUG] JReadFloat '-2.5' -> {}", v);
                success = false;
    
        // Must advance (token consumed) and yield exactly 7.0 -- not 42.0.
        if (StrIterIndex(&out) == StrIterIndex(&si)) {
            WriteFmtLn("[DEBUG] JReadFloat did not advance on integer '7'");
            success = false;
        StrIter out = JReadFloat(si, &val);
    
        if (StrIterIndex(&out) == StrIterIndex(&si)) {
            WriteFmtLn("[DEBUG] JReadFloat did not advance on integer '13'");
            success = false;
    
        // Malformed -> iterator rewinds (no advance).
        if (StrIterIndex(&out) != StrIterIndex(&si)) {
            WriteFmtLn("[DEBUG] JReadNull advanced on malformed 'nuII'");
            success = false;
        StrIter out     = JReadNull(si, &is_null);
    
        if (!(is_null == true && StrIterIndex(&out) == 4)) {
            WriteFmtLn("[DEBUG] JReadNull 'null' value/advance wrong: n={}, idx={}", is_null, StrIterIndex(&out));
            success = false;
    
        if (!(is_null == true && StrIterIndex(&out) == 4)) {
            WriteFmtLn("[DEBUG] JReadNull 'null' value/advance wrong: n={}, idx={}", is_null, StrIterIndex(&out));
            success = false;
        }
    
        // After skipping "xy" and the LF, the iterator sits on 'Z' at index 3.
        result = result && (StrIterIndex(&si) == 3);
        result = result && StrIterPeek(&si, &c) && (c == 'Z');
    
        // "a" then one LF consumed -> index 2, sitting on the second LF.
        result = result && (StrIterIndex(&si) == 2);
        result = result && StrIterPeek(&si, &c) && (c == '\n');
        bool             result = true;
    
        result = result && (StrIterIndex(&si) == StrIterLength(&si));
        result = result && (MapPairCount(&cfg) == 2);
        result = result && KvConfigGetI64(&cfg, "a", &a) && (a == 1);
        bool    result = true;
    
        result = result && (StrIterIndex(&si) == StrIterLength(&si));
        result = result && (MapPairCount(&cfg) == 2);
        result = result && KvConfigGetI64(&cfg, "a", &a) && (a == 1);
        // Parse must fail on the bad line -> iterator stays at origin and the
        // key is not stored.
        result = result && (StrIterIndex(&si) == 0);
        result = result && !KvConfigContains(&cfg, "k");
        bool             result = true;
    
        result = result && (StrIterIndex(&si) == StrIterLength(&si));
        result = result && (MapPairCount(&cfg) == 1);
        v      = KvConfigGetPtr(&cfg, "k");
        bool    result = true;
    
        result = result && (StrIterIndex(&si) == StrIterLength(&si));
        result = result && (MapPairCount(&cfg) == 1);
        v      = KvConfigGetPtr(&cfg, "k");
        bool             result = true;
    
        result = result && (StrIterIndex(&si) == StrIterLength(&si));
        result = result && (MapPairCount(&cfg) == 1);
        result = result && KvConfigContains(&cfg, "k");
        bool    result = true;
    
        result = result && (StrIterIndex(&si) == StrIterLength(&si));
        result = result && (MapPairCount(&cfg) == 3);
        result = result && KvConfigContains(&cfg, "host");
        bool    result = true;
    
        result = result && (StrIterIndex(&si) == StrIterLength(&si));
        result = result && (MapPairCount(&cfg) == 4);
        result = result && path && StrCmp(path, "/srv/my app") == 0;
        bool    result  = true;
    
        result = result && (StrIterIndex(&si) == 0);
        result = result && KvConfigGetBool(&cfg, "valid", &enabled) && enabled;
        result = result && !KvConfigContains(&cfg, "later");
        name = KvConfigGetPtr(&cfg, "name");
    
        result = result && (StrIterIndex(&si) == StrIterLength(&si));
        result = result && (MapPairCount(&cfg) == 3);
        // The CR must not survive in the parsed value.
Last updated on