12345678Build a ball pit · Step 6 of 8
Remember things
You'll learn
- Open a store with
storage.open - Work with handles that wait
- Wait for a result with
:ready()
- Time
- 10 min
- Builds on
- Step 5: Make it a package
- File
ballpit/init.lua
Close the window and the pit forgets its balls. In this step your app saves how many balls the pit holds, and starts with that many the next time it runs.
Read and save the count
datumhue.storage.open opens your app's own store: bytes kept under
names you choose, still there after your app quits. The store belongs to
your package. The same package finds the same data on every run, and no
other app can open it.
A store answers in its own time. Storage:get returns at once, before
the value is read, with a handle the value arrives in. :ready() on
that handle pauses your code until the value is there, then returns the
handle. Change ballpit/init.lua to this:
local pit = require("pit")
local toolbar = require("toolbar")
local screen = datumhue.ui.root:panel({
width = "100%",
height = "100%",
flex_direction = "column",
justify_content = "center",
align_items = "center",
gap = 12,
})
toolbar.new(screen)
pit.mount(screen)
New line: local store = datumhue.storage.open()
New line: local saved = store:get("balls"):ready().value
New line: local start = 10
New line: if saved then
New line: start = saved:json()
New line: print("Welcome back: " .. start .. " balls")
New line: end
New line:
New line: pit.on_change(function(n)
New line: store:set("balls", datumhue.bytes.json(n))
New line: end)
New line:
New line: for _ = 1, start do
pit.add()
end
In this example: datumhue.ui.root UiElement:panel datumhue.storage.open Storage:get BytesFetch:ready BytesFetch.value Bytes:json Storage:set datumhue.bytes.json
store:get("balls")asks for what the store keeps under the nameballs, and:ready()waits for it. The handle'svalueis the stored bytes, ornilon the first run, when there are none.- A store keeps bytes.
Bytes:jsonreads the bytes back as the number they hold, anddatumhue.bytes.jsonturns a number into bytes. - The listener saves each new count.
Storage:setstarts the write and returns at once, with a handle of its own, anOp. You could wait for the write with its:ready(). Here nothing needs to, and the write happens all the same. - On the first run the pit starts with ten balls, as before.
While :ready() waits, the rest of your app waits with it, but nothing
else does: the workstation keeps showing your window, and other apps
keep running. A store usually answers within a frame.
Waiting: suspending calls and handles lists
the ways to wait, and how to wait for several handles at once.
Run it again
Add a few balls, close the window, and run the package again:
$ datumhue run ballpit
The pit starts with as many balls as you left in it, and the terminal
says how many, such as Welcome back: 10 balls. Clear the pit before
you close it, and the next run starts empty: 0 is a count too.
The store stays on this workstation. Save data between runs shows the stores a package can share with other apps.
Try this
- Take
:ready()off thegetline and run the package. What does the error say? - Add a Reset button that deletes the saved count with
Storage:delete, so the next run starts with ten balls again. - Count how many times the app has started, under a name of its own, and show the number in the toolbar.
Recap
datumhue.storage.openopens a store that keeps your package's data between runs.- A store keeps bytes:
datumhue.bytes.jsonandBytes:jsonturn values into bytes and back. Storage:getreturns a handle at once, and:ready()waits until its value is there.Storage:setstarts a write that happens whether or not you wait for it.
New in this step