CborElement API #3165
Replies: 7 comments 11 replies
-
|
That's the first discussion we have here, at least the one about the API design, so feel free to suggest anything that'll improve it. |
Beta Was this translation helpful? Give feedback.
-
Tags representationThe CBOR format of kotlinx.serialization already uses UByteArray as part of its public API. Hence I fail to see the issue. |
Beta Was this translation helpful? Give feedback.
-
Concerns about the mutability of (byte) arraysI feel like this is trying to work around a fundamental characteristic of the Kotlin language. Feels somewhat off, as this is not for a serialization format to address, but rather the topic of a KEEP |
Beta Was this translation helpful? Give feedback.
-
CborElement has protected value property, its inheritors override it and make publicI am really undecided on this as well, because there a two ways to view this:
I feel both takes are legit, but I tend to favour the second one because Kotlin is our ground truth, not CBOR. I don't have a good Idea how to fix it… |
Beta Was this translation helpful? Give feedback.
-
CborNullAsEmptyMap annotation#3126 is already integrated. In other words: |
Beta Was this translation helpful? Give feedback.
-
Asymmetric Tag Handling
I feel like this is more of a general disambiguation issue, that also hit ASN.1, but on steroids. See here. Could be I'm mixing things up from your description, but if this is about ambiguitiy, fixing it for CBOR should be ridiculously easy compared seven layers of insanity wrapping ASN.1 disambiguation. |
Beta Was this translation helpful? Give feedback.
-
CborEncoder API extension AsymmetryI thin this issue would really benefit from a human (and not an AI) that is not me opening the current state in IDEA and check it out. There is an 80% chance I just messed this up for no reason and we can easily fix it and make the APIs of encoder and decoder symmetric, but I don't see it. This is all I am willing to spell out about this issue, even though I have a strong opinion, because a neutral pair of eyes on this, and some playing around with it has the potential to work wonders and me being more concrete may sabotage this. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
There's a proposal by @JesusMcCloud to add an API to process CBOR documents without mapping them directly to user defined Kotlin objects, similar to what
JsonElementis for JSON: #3036The goal of this discussion is to find solutions to open design issues, the implementation of which will lead to the integration of #3036.
Motivation
See #3036 and referred issues for more details on the motivation, but in general, some protocols built on top of CBOR (like COSE) could not be easily mapped to an object model compatible with what
kotlinx-serialization-cboralready supports.To be more precise, COSE defines a CBOR-protocol, where:
Parameter values within a header map are polymorphic, for instance:
Here, the algorithm identifier is either an
int, or atext string. The COSE implies that a CBOR data item’s header will work here as a discriminator (i.e., there is no additional metadata helping to guess a type of an item before reading it).However, with the API kotlinx-serialization is currently providing, the only way to decode such a polymorphic value is by trying to read an
int, and if read fails with an exception, fall back to reading astring.This approach is error prone (after getting an exception, the decoder may be in a state that prevents further reading) and it makes sense to provide a more convenient API to work with it and with any other similar CBOR-protocols.
Refer to RFC 8949 for details about the CBOR format.
Refer to RFC 8152 for details about the COSE protocol.
Proposed solution
The API proposed in #3036 solves challenges related to working with the CBOR-based protocols like COSE.
However, there are few open design questions that has to be address before merging the PR into the mainline.
Open questions
CborElement has protected value property, its inheritors override it and make public
It works for some types (like
CborStringorCborFloat), it does not make sense for others (likeCborNullandCborUndefined).For
CborInteger, the actual value is the(absoluteValue, sign)tuple, and it makes sense to useabsoluteValueas the property name, instead of sign.CborByteString exposes value as a ByteArray
CborByteString’shashCodeandequalsdepend on the value of the underlyingByteArray, but theByteArrayitself is mutable.The public accessor should create a copy on each access, and it should probably be a function like
.toByteArray. Optionally, we can provide some iterator over bytes, to avoid copying data.Tags representation
Currently, element’s tags are publicly accessible via
tags: ULongArrayproperty. There are two issues withULongArray:hashCodeandequalsdepend on tags)We should not expose it this way, and even if element tags will be represented as a flat list, they should rather be some immutable collection.
Another tag-related issue is that tags are currently assigned to an element as a flat list. It is consistent with how tags could be specified using
KeyTags/ValueTags/ObjectTags.At the same time, if an element has multiple tags, these CBOR tags are nested (https://cborbook.com/part_1/cbor_tags.html#tag-nesting).
So tags are not just random permutations of different values, their order matters as different orders mean different things.
When tags are represented as a flat list, it is not clear how such a nesting will be encoded (or represented after decoding).
Some tags (https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml) could be applied to different major types, so the scenario when multiple tags are associated with an element should not be that rare.
An alternative approach is representing each tag as a wrapper around a tagged element:
See how the same example from https://cborbook.com/part_1/cbor_tags.html#tag-nesting will be represented using these two approaches:
It’s an open question how well each of these APIs is suited for practical use-cases.
KeyTags/ValueTags/ObjectTagsand CborElement relationEncoding/decoding behavior is not explicitly specified for
CborElement-typed properties/values andKeyTags/ValueTags/ObjectTags.Effectively, tags from the annotation will be prepended before tags associated with
CborElement. At the same time, the validation will fail (when enabled) during deserialization, creating an asymmetry - a taggedCborElementvalue will be successfully serialized as a property annotated withValueTags, but its deserialization will fail because of mismatching tags.The behavior should be explicitly specified.
CborNullAsEmptyMap annotation
Previously, we discussed that representing nulls as empty maps was required only to simplify COSE documents processing and that
CborElementAPI will cover it.Is this annotation still needed after providing the
CborElementAPI? Can it be removed? Can those who need such behavior implement a custom serializer instead?CborArray->CborObjectAsArrayrenamingIt seems like we can start a short
CborArraydeprecation cycle right now, without waiting for the wholeCborElementAPI, can’t we?CborEncoder API extension
CborEncoderAPI was extended with following functions:encodeUndefinedencodePositiveencodeNegativeencodeByteStringencodeTagsencodeCborElementAt the same time,
CborDecodergot only thedecodeCborElementfunction.It creates an asymmetry between encoder and decoder.
And it is also not clear why encoder needs anything but
encodeCborElement, if the decoder works perfectly on that level.Can we trim down the
CborEncoderAPI to justencodeCborElement?Miscellaneous
There are some other non-API related topics like documentation improvements, or test coverage improvement, but those should not affect the public API and could be addressed separately.
Beta Was this translation helpful? Give feedback.
All reactions