1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
|
# Gio support
Most of the Gio facilities are supported natively through
gobject-introspection layer. However, lgi provides `Gio.Async` which
help in using Gio-style asynchronous I/O operations.
## Asynchronous IO support
Native Gio asynchronous operations are based on traditional callback
scheme, i.e. the operation is started, pushed to be performed on the
background and when it finishes, it calls registered callback with
operation results as arguments. While this scheme is widely used for
asynchronous programming, it leads to spaghetti code full of
callbacks. Lua provides coroutines, which can be used to make the
code look 'synchronous' again, but still retaining the advantage of
non-blocking I/O operations.
Gio-style asynchronous functions come as pair of two methods;
`name_async` which starts operation and registers callback, and
`name_finish`, which should be called in the context of registered
callback and allows retrieveing operation results. When `Gio`
override is loaded, lgi detects any of these pairs (in any object, not
just from Gio namespace) and when found, it synthesizes `async_name`
operations, which wraps native methods and uses Lua coroutines to
convert callbacks into synchronous code. In order for `async_method`
to work, these methods have to be called in the context of functions
called through `Gio.Async` spawning facilities; either
`Gio.Async.call` for synchronous calls and `Gio.Async.start` for
starting routine on background.
### Gio.Async class
This helper class implemented by lgi (not originating from
introspected Gio module) contains interface for using lgi asynchronous
support. This class contains only static methods and attributes, it
is not possible to instantiate it.
### Gio.Async.call and Gio.Async.start
local call_results = Gio.Async.call(user_function[, cancellable[, io_priority])(user_args)
local resume_results = Gio.Async.start(user_function[, cancellable[, io_priority])(user_args)
These methods accept user function to be run as argument and return
function which starts execution of the user function in async-enabled
context.
Any `async_name` methods called inside context do not accept
`io_priority` and `cancellable` arguments (as their `name_async`
original counterparts do), instead global cancellable and io_priority
values given as arguments to `Gio.Async.call/start` are used.
### Gio.Async.cancellable and Gio.Async.io_priority
Code running inside async-enabled context can query or change value of
context-default `cancellable` and `io_priority` attributes by getting
or setting them as attributes of `Gio.Async` class.
If `cancellable` or `io_priority` arguments are not provided to
`Gio.Async.start` or `Gio.Async.call`, they are automatically
inherited from currently running async-enabled coroutine, or default
values are used (if caller is not running in async-enabled context).
### Simple asynchronous I/O example
Following example reacts on the press of button, reads contents of
`/etc/passwd` and dumps it to standard output.
local window = Gtk.Window {
... Gtk.Button { id = 'button', label = 'Breach' }, ...
}
function window.child.button:on_clicked()
local function dump_file(filename)
local file = Gio.File.new_for_path(filename)
local info = file:async_query_info('standard::size', 'NONE')
local stream = file:async_read()
local bytes = stream:async_read_bytes(info:get_size())
print(bytes.data)
stream:async_close()
end
Gio.Async.start(dump_file)('/etc/passwd')
end
Note that all reading happens running on background, on_clicked()
handler finished when the operation is still running on background, so
if you have a few gigabytes worth /etc/passwd file, the application
will not freeze while dumping it.
`samples/giostream.lua` provides far more involved sample illustrating
use of asynchronous operations.
|