The general process of serialisation is the conversion of a data or array instance into some form that can be written to disk or transmitted over a network. There are various ways to do this, such as a JSON encoder, or the design of your own serialisation format aided by the reflective operators that Dana provides.
Dana can automatically provide a direct byte array representation of Data instances, as long as the Data type includes only fields of primitive type (including static arrays).
This is done by using the notation dana.serial(x). This operation returns a reference to a byte array which has the contents of x as a stream of bytes. This byte array reference is readable and writable, allowing the individual bytes of a data instance to be modified.
As an example, we could write a data instance to file like this:
data Person {
char name[50]
int4 age
}
Person p = new Person()
p.name = "sam"
p.age = 26
byte stream[] = dana.serial(p)
File fd = new File("myfile.data", File.CREATE)
fd.write(stream)
The byte array that dana.serial() returns has the data instance's fields laid out in plain contiguous memory; the Person type is therefore 54 bytes long in its serial form (50 bytes of the name array, then 4 bytes of the age field).
We could then read our data back from the file by again getting a serial byte array representation, then copying another byte array (read from the file) into that one:
Person p = new Person()
byte stream[] = dana.serial(p)
File fd = new File("myfile.data", File.READ)
stream =[] fd.read(stream.arrayLength)
When doing direct serialisation in this way, it is often good practice to only use explicitly-sized types in your data instance fields. In the above example we have used an int4 rather than an int, because the int type has a variable size in memory depending on the bit-width of the host computer's CPU. If we therefore wrote binary serialised data that included an int on a 64-bit machine, and read that data back on a 32-bit machine, we would then get undefined results.
Finally, note that the serial byte array representation of a data instance is live; it is not a copy of the data instance bytes but is a memory reference to those bytes. Going back to our first example, the following code therefore has exactly the same result:
Person p = new Person()
byte stream[] = dana.serial(p)
p.name = "sam"
p.age = 26
File fd = new File("myfile.data", File.CREATE)
fd.write(stream)
Because the byte array representation is a direct reference to an instance's memory, we can often re-use the same data instance to read or write many serial records in a row.