Serialization
Sric supports serialization through built-in dynamic reflection, using the HiML text format.
Serialization Example
Classes to be serialized require the reflect
marker:
reflect struct Point {
var x: Int
var y: Float
}
unsafe fun testSimple() {
var encoder: Encoder
var obj = new Point { .x = 1; .y = 2; }
var t = obj as *Void;
var res = encoder.encode(t, "testSerial::Point")
printf("%s\n", res.c_str())
var decoder: Decoder
var p = decoder.decode(res)
var obj2: raw* Point = unsafeCast$<raw*Point>(p)
verify(obj2.x == obj.x)
verify(obj2.y == obj.y)
}
For non-polymorphic objects like Point, the type name "testSerial::Point" must be explicitly provided.
Skipping Serialization
Use Transient annotation to exclude fields:
reflect struct Point {
var x: Int
//@Transient
var y: Float
}
Dynamically decide using the _isTransient method.
reflect struct Point {
var x: Int
fun _isTransient(): Bool {
return false
}
}
Post-Deserialization Handling
The _onDeserialize method is automatically called after deserialization:
reflect struct Point {
var x: Int
fun _onDeserialize() {
}
}
Simple Serialization Mode
Normally custom classes serialize as HiML objects. The SimpleSerial
annotation enables string serialization (e.g. "1 2 3 4" instead of structured formatInsets{top=1,right=2,bottom=3,left=4}
):
//@SimpleSerial
reflect struct Insets {
var top: Int = 0
var right: Int = 0
var bottom: Int = 0
var left: Int = 0
fun toString() : String {
return String::format("%d %d %d %d", top, right, bottom, left)
}
fun fromString(str: String): Bool {
var fs = str.split(" ")
if (fs.size() == 4) {
top = fs[0].toInt32()
right = fs[1].toInt32()
bottom = fs[2].toInt32()
left = fs[3].toInt32()
return true
}
return false
}
}
Serialization/deserialization automatically calls toString
and fromString
- these methods must exactly match the shown signatures.