tink_json
tink_json copied to clipboard
Integer constants as enums
As far as I can see, there's no way of parsing target as an enum in the following example:
"bufferViews": [
{
"buffer": 0,
"byteOffset": 576,
"byteLength": 72,
"target": 34963
},
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 576,
"byteStride": 12,
"target": 34962
}
],
The following results in [haxe] invalid use of @:json
enum BufferTarget {
@:json(34963) ElementArrayBuffer;
@:json(34962) ArrayBuffer;
}
Right now I'm using an enum abstract, but I think it would be more elegant if something like the above were possible.
Well, the way it's "supposed to work" is more like:
enum Buffer {
@:json({ target: 34963 }) ElementArrayBuffer(elementArrayBuffer:{ buffer:Int, byteOffset:Int, byteLength:Int });
@:json({ target: 34962 }) ArrayBuffer(arrayBuffer:{ buffer:Int, byteOffset:Int, byteLength:Int, byteStride:Int });
}
The point being that the byteStride is actually only there if needed. But I'll look into making it possible this way ;)
Hmm, I can see why it would be better to do it like this (as indeed byteStride is only there for ArrayBuffer), but then you can't access, say, the buffer property of an arbitrary buffer without first using a switch to extract it, even though any buffer will have this property.
Well, could solve that with abstracts or static extensions, but without really knowing the use case I can hardly give qualified advise ^^
That said, I will look into making this possible per @:json. Right now you can do something like this:
//BufferTarget.hx
package whatever;
class BufferTargetParser {
public function new(_) {}
public function parse(value:Int):BufferTarget
return switch value {
case 34963: ElementArrayBuffer;
case 34962: ArrayBuffer;
default: throw 'Invalid buffer target $value';
}
}
@:jsonParse(whatever.BufferTarget.BufferTargetParser)//must be fully qualified name
enum BufferTarget {
@:json(34963) ElementArrayBuffer;
@:json(34962) ArrayBuffer;
}
Here are the tests for custom parsing and stringifying
Ah, I didn't know you could that. I solved it like this now:
typedef BufferViewRaw = {
var buffer : Int;
var byteLength : Int;
var byteOffset : Int;
var target : Int;
@:optional var byteStride : Int;
}
@:jsonParse(gltf.GLTFLoader.BufferViewParser)
typedef BufferView = {
var buffer : Int;
var byteLength : Int;
var byteOffset : Int;
var target : BufferTarget;
}
class BufferViewParser {
public function new(_) {}
public function parse(v:BufferViewRaw):BufferView {
return {
buffer: v.buffer,
byteLength: v.byteLength,
byteOffset: v.byteOffset,
target: switch v.target {
case 34963: ElementArrayBuffer;
case 34962: ArrayBuffer(v.byteStride == null ? Tight : Fixed(v.byteStride));
default: throw 'Invalid buffer target ${v.target}';
}
};
}
}
enum BufferTarget {
ElementArrayBuffer;
ArrayBuffer(stride : Stride);
}
It's a bit bulky this way, but I think the final type it gets makes more sense. Though the :json modification would still be helpful for standalone enums that don't influence which other fields there are.