Description
Addresses #47 in part by proposing a mid-level API. The possibility for a higher level API is left open.
File API
The mid-level file API aims to implement File I/O on top of the raw JS apis found here: https://w3c.github.io/FileAPI/ which includes listing files, creating files, and reading files.
General Differences
In general this API will mostly differ from the web_sys
interface in the following ways:
No js_sys Types
js_sys tends to be fairly "stringly" typed, so where we have known enums, the crate will provide bespoke types.
This is also true for errors which are usually exposed as JsValues. In this crate they will be exposed as well-formed Rust types.
Callbacks
All callbacks will be of the appropriate closure type (e.g., FnOnce).
The API
FileList
JS provides a basic collection type over files (usually from an tag). In general FileList
will be an opaque struct that offers a rich interface to the collection through an Iterator
implementation.
Blob
Blob
is a "file like" interface. The crate would expose this as a Rust interface from which the specific types File
and RawData
inherit. These types would be roughly 1 to 1 translations of the File
and Blob
objects just with less "stringly" typed interfaces. For example, RawData
would accept a known list of mime-types
FileReader
The FileReader API is a bit wonky and can easily be used in the incorrect way. For instance, if the user calls readAsArrayBuffer
or other "read" APIs before the data is loaded, the operation won't return data. The crate will expose an API that more properly models the "read" state machine.
This will be done through a futures API which takes the user through the state machine:
let file_reader = FileReader::new();
file_reader.read_as_text(&blob).map(move |contents| {
element.set_inner_html(contents);
})
The various "read" methods will take ownership of self
so that users can't try to read multiple files at once. These methods return an InProgressRead
struct that is a future and also contains an abort
method for aborting the upload.
The events "error", "load", and "loadend" are all representable through the future and thus aren't exposed on the file reader. The events "progress", "loadstart", and "abort" are still exposed as methods that take the appropriate Rust closure.
FileReaderSync
This API would mirror the future based API just in a different namespace.
Drawbacks, Rationale, and Alternatives
FileReader exposes a very different API from its JS counterpart. We could do a more 1 to 1 translation of the API and leave the improved API for a higher-level crate. This would make this crate only a very marginal improvement on what is already exposed in js_sys
.
Unresolved Questions
Is there an ergonomic way to expose FileReader "progress", "loadstart", and "abort" events as part of the future API?
Is there a better way to model the relationship between Blob
and File
? Possibilities include an enum and a File
type which contains a Blob
type.