Skip to content

Data Management & Utilities

For applications that require complex data structures, centralized state, or network communication, Vulpis provides lightweight utility modules to keep your code organized and reactive.

Global Store (store.lua)

While useState is excellent for isolated UI toggles, calling it for dozens of variables across a large application can become tedious. The store.lua utility allows you to create centralized, global application state alongside the actions that mutate it.

store.create(setup_function)

Initializes a global store. It wraps your state and automatically handles engine re-renders whenever the state is modified.

  • Parameters:
    • setup_function: A function that receives get and set methods and returns your initial state table and actions.
  • Returns: A custom useStore() hook that your UI components can call to read the data.

Understanding get and set

Inside your setup_function, Vulpis provides two critical helper functions: get and set. These are the strictly enforced methods for interacting with your global state from within your custom actions.

1. get(): Reading the State

The get function returns a snapshot of your entire current state table.

Why you need it: When you write an action to update a value, you often need to know what the value is right now before you can change it. get() gives you that current data safely.

lua
-- Example inside a store action:
local currentState = get() 
print("The current score is: " .. currentState.score)

2. set(updates): Writing the State

The set function is how you modify your state. Instead of passing the entire state object back, you only pass a table containing the specific variables you want to update (similar to a "patch" or partial update).

The "Magic" of set:set doesn't just change variables; it performs two crucial background tasks to keep your app fast:

  1. Smart Diffing: It compares your new values against the old ones. If you try to set score = 10 but the score is already 10, it ignores the update.
  2. Auto-Reconciliation: If a value does change, set automatically calls vulpis.markDirty() for you. This guarantees the C++ engine knows about the change and will efficiently re-render the UI on the next frame.

Creating and Using a Store

Here is how get and set work in tandem. You use get() to calculate the new value, and set() to securely save it and trigger a UI update.

lua
local store = require("utils.core.store")
local el = require("utils.core.elements")

-- 1. Define the store and its actions
local useGameStore = store.create(function(get, set)
    return {
        -- The State
        score = 0,
        playerName = "Hero",
        
        -- The Action
        addScore = function(points)
            -- READ: What is our score right now?
            local current = get()
            
            -- CALCULATE: Add the new points
            local newScore = current.score + points
            
            -- WRITE: Apply the changes (automatically calls markDirty!)
            set({ score = newScore })
        end
    }
end)

-- 2. Consume the store in your UI
function App()
    -- Read the data via the generated hook
    local gameState = useGameStore()
    
    return el.VBox({
        style = { gap = 10, padding = 20 },
        children = {
            el.Text("Player: " .. gameState.playerName),
            el.Text("Score: " .. gameState.score),
            
            el.Button({
                text = "Add 10 Points",
                onClick = function()
                    -- Trigger the action
                    gameState.addScore(10)
                end
            })
        }
    })
end

JSON Parser (json.lua)

When interacting with external APIs, saving complex configurations, or using WebSockets, you must convert between Lua tables and JSON strings. The json.lua module is a robust, lightweight utility for serialization and deserialization.

json.encode(val)

Converts a Lua value into a JSON string.

  • Supports: Tables (sparse arrays and objects), strings, numbers, booleans, and nil.
  • Safety: Automatically handles escape characters and detects circular references.

json.decode(str)

Parses a JSON string back into a native Lua table.

  • Supports: Full deserialization of JSON arrays [], objects {}, strings (including unicode escapes like \uXXXX), literals (true, false, null), and numbers.
  • Error Handling: Throws detailed error messages with line and column counts if the JSON string is malformed.

Usage Example:

lua
local json = require("utils.core.json")

-- Encoding a Lua Table to JSON
local playerData = {
    name = "VulpisUser",
    level = 42,
    inventory = {"Sword", "Shield"}
}

local jsonString = json.encode(playerData)
print(jsonString) 
-- Output: {"name":"VulpisUser","inventory":["Sword","Shield"],"level":42}


-- Decoding a JSON string back to Lua
local payload = '{"status":"success", "data": {"points": 150}}'
local parsed = json.decode(payload)

if parsed.status == "success" then
    print("Earned points: " .. parsed.data.points)
end