void tr_variantWalk(tr_variant const* v, struct VariantWalkFuncs const* walkFuncs, void* user_data, bool sort_dicts)
{
    int stackSize = 0;
    int stackAlloc = 64;
    struct SaveNode* stack = tr_new(struct SaveNode, stackAlloc);

    nodeConstruct(&stack[stackSize++], v, sort_dicts);

    while (stackSize > 0)
    {
        struct SaveNode* node = &stack[stackSize - 1];
        tr_variant const* v;

        if (!node->isVisited)
        {
            v = node->v;
            node->isVisited = true;
        }
        else if (tr_variantIsContainer(node->v) && node->childIndex < node->v->val.l.count)
        {
            int const index = node->childIndex;
            ++node->childIndex;

            v = node->v->val.l.vals + index;

            if (tr_variantIsDict(node->v))
            {
                tr_variant tmp;
                tr_variantInitQuark(&tmp, v->key);
                walkFuncs->stringFunc(&tmp, user_data);
            }
        }
        else /* done with this node */
        {
            if (tr_variantIsContainer(node->v))
            {
                walkFuncs->containerEndFunc(node->v, user_data);
            }

            --stackSize;
            nodeDestruct(node);
            continue;
        }

        if (v != NULL)
        {
            switch (v->type)
            {
            case TR_VARIANT_TYPE_INT:
                walkFuncs->intFunc(v, user_data);
                break;

            case TR_VARIANT_TYPE_BOOL:
                walkFuncs->boolFunc(v, user_data);
                break;

            case TR_VARIANT_TYPE_REAL:
                walkFuncs->realFunc(v, user_data);
                break;

            case TR_VARIANT_TYPE_STR:
                walkFuncs->stringFunc(v, user_data);
                break;

            case TR_VARIANT_TYPE_LIST:
                if (v == node->v)
                {
                    walkFuncs->listBeginFunc(v, user_data);
                }
                else
                {
                    if (stackAlloc == stackSize)
                    {
                        stackAlloc *= 2;
                        stack = tr_renew(struct SaveNode, stack, stackAlloc);
                    }

                    nodeConstruct(&stack[stackSize++], v, sort_dicts);
                }

                break;

            case TR_VARIANT_TYPE_DICT:
                if (v == node->v)
                {
                    walkFuncs->dictBeginFunc(v, user_data);
                }
                else
                {
                    if (stackAlloc == stackSize)
                    {
                        stackAlloc *= 2;
                        stack = tr_renew(struct SaveNode, stack, stackAlloc);
                    }

                    nodeConstruct(&stack[stackSize++], v, sort_dicts);
                }

                break;

            default:
                /* did caller give us an uninitialized val? */
                tr_logAddError("%s", _("Invalid metadata"));
                break;
            }
        }
    }

    tr_free(stack);
}
void tr_variantWalk(tr_variant const* v, struct VariantWalkFuncs const* walkFuncs, void* user_data, bool sort_dicts)
{
    int stackSize = 0;
    int stackAlloc = 64;
    struct SaveNode* stack = tr_new(struct SaveNode, stackAlloc);

    nodeConstruct(&stack[stackSize++], v, sort_dicts);

    while (stackSize > 0)
    {
        struct SaveNode* node = &stack[stackSize - 1];
        tr_variant const* v;

        if (!node->isVisited)
        {
            v = node->v;
            node->isVisited = true;
        }
        else if (tr_variantIsContainer(node->v) && node->childIndex < node->v->val.l.count)
        {
            int const index = node->childIndex;
            ++node->childIndex;

            v = node->v->val.l.vals + index;

            if (tr_variantIsDict(node->v))
            {
                tr_variant tmp;
                tr_variantInitQuark(&tmp, v->key);
                walkFuncs->stringFunc(&tmp, user_data);
            }
        }
        else  
        {
            if (tr_variantIsContainer(node->v))
            {
                walkFuncs->containerEndFunc(node->v, user_data);
            }

            --stackSize;
            nodeDestruct(node);
            continue;
        }

        if (v != NULL)
        {
            switch (v->type)
            {
            case TR_VARIANT_TYPE_INT:
                walkFuncs->intFunc(v, user_data);
                break;

            case TR_VARIANT_TYPE_BOOL:
                walkFuncs->boolFunc(v, user_data);
                break;

            case TR_VARIANT_TYPE_REAL:
                walkFuncs->realFunc(v, user_data);
                break;

            case TR_VARIANT_TYPE_STR:
                walkFuncs->stringFunc(v, user_data);
                break;

            case TR_VARIANT_TYPE_LIST:
                if (v == node->v)
                {
                    walkFuncs->listBeginFunc(v, user_data);
                }
                else
                {
                    if (stackAlloc == stackSize)
                    {
                        stackAlloc *= 2;
                        stack = tr_renew(struct SaveNode, stack, stackAlloc);
                    }

                    nodeConstruct(&stack[stackSize++], v, sort_dicts);
                }

                break;

            case TR_VARIANT_TYPE_DICT:
                if (v == node->v)
                {
                    walkFuncs->dictBeginFunc(v, user_data);
                }
                else
                {
                    if (stackAlloc == stackSize)
                    {
                        stackAlloc *= 2;
                        stack = tr_renew(struct SaveNode, stack, stackAlloc);
                    }

                    nodeConstruct(&stack[stackSize++], v, sort_dicts);
                }

                break;

            default:
                 
                tr_logAddError("%s", _("Invalid metadata"));
                break;
            }
        }
    }

    tr_free(stack);
}