Is there any guide on how to write custom formats?
# serialization
a
Is there any guide on how to write custom formats?
r
You can find some details in talks the JB team has given.

https://www.youtube.com/watch?v=IhKTIFlNrC4

https://www.droidcon.com/media-detail?video=362742516 But note that some details have changed in 0.20.0. For example the NamedEncoder/Decoder family are no longer considered public API, and they're recommending using AbstractEncoder/Decoder instead
a
@russhwolf Are there any docs for them? I'm having some trouble implementing them, for example, if i want to write the
AbstractEncoder/Decoder
that would convert to and from a
List<Any?>
where would i instantiate and retrieve the list instance from? and what does beginning and ending a structure mean?
Copy code
class ListEncoder : AbstractEncoder() {

    override fun beginStructure(
        descriptor: SerialDescriptor,
        vararg typeSerializers: KSerializer<*>
    ): CompositeEncoder {
        // What to do here?
    }

    override fun encodeString(value: String) {
        [list???].add(value) // Where to instantiate list
    }

    ...
}

class ListDecoder : AbstractDecoder() {

    override fun beginStructure(
        descriptor: SerialDescriptor,
        vararg typeSerializers: KSerializer<*>
    )CompositeDecoder {
        // What to do here?
    }

    override fun decodeString(): String {
        [list???].get(0) // Where to retrieve list from
    }

    ...

}
r
Not aware of much in the way of docs, and I haven't done enough to have a ton of insight. I had some stuff working with NamedEncoder/Decoder that I have not yet managed to translate well to the Abstract APIs. You can look at the internals of the existing stuff to get some insights, but it's frustrating because a lot of them don't use the Abstract classes so you can't do the same things in your code that does.
I'm having trouble following what you want to do with List, but something to try is initializing a list in
beginStructure()
that you can then add to in
encode()
. For
decode()
, you could supply the existing list to the decider and then read from it.
a
The list was just an example, i'm trying to convert to and from Parcelable for Android, still not entirely sure if it's possible though, a Bundle is probably a better idea.
r
Yeah I'd think
Bundle
would be the way to go. Would be reasonably straightforward with the
Named
classes. The hard part with
Abstract
is managing the key names and I haven't fully wrapped my head around that
a
Yeah, not sure how that would work without names or even indexes.
r
You have to do a lot of manual tracking. eg you can read the element name in
encodeElement()
but then you have to cache that somewhere so you can reference it in
encodeValue()
. Even more awkward on
decode()
because you have to do your own counting. It's frustrating because the `CompositeEncoder`/`Decoder` APIs include the descriptor which would make this much easier but they aren't overrideable
👏 1
a
I did find notice the
encodeElement()
method but didn't find a similar one for the decoder so i dismissed it, looks like we have to do some weird stuff to get this to work lol . Not sure why those are final or why NamedEncoders/Decoders were made internal though, the lack of docs make this even more frustrating.
@russhwolf Hi again, Did you manage to get you decoder to work with lists? My encoder encodes them just fine with their index as the key. However, the decoder's
SerialDescriptor#elementCount
always returns 1 for lists, which makes sense as it doesn't know how many element this list has, but it makes it unreliable if you want to check when to stop incrementing the index and just return -1.
r
I haven't dug into this in a couple weeks actually. Might take a look over the weekend but I also have other projects higher on my list
You might need to encode list size as a separate item in your bundle.
a
Yup, ended up doing that with
$size
as key to avoid collisions for StructureKind LIST/MAP, works fine for now.