-
Notifications
You must be signed in to change notification settings - Fork 1
feat: support for CBOR #32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
gmega
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Besides the comments, I strongly believe we need to deal with the nim-serde pragmas in some way, even if they're not supported. A few options:
- issue an error (preferably a compilation error, if possible) if you try to use an annotated type with CBOR. This is what I prefer. Safest, least likely to cause surprise;
- add documentation describing the behavior. Better than nothing, can still cause surprise, at least is written somewhere.
Either way, the documentation needs to be updated. I'm sure @emizzle will have better suggestions than mine as to how to make this integration as seamless as possible.
serde/cbor/deserializer.nim
Outdated
| return failure(newCborError("Expected positive integer, got " & $c.kind)) | ||
| let val = c.intVal.BiggestUInt | ||
|
|
||
| ?c.next() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm honestly not very fond of this. Took me a bit to figure out what this was doing, and I don't think I've seen this being used like that elsewhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
serde/cbor/deserializer.nim
Outdated
| let n = c.s.readData(buf[0].addr, buf.len) | ||
| if n != buf.len: | ||
| return failure(newCborError("truncated read of CBOR data")) | ||
| tryNext(c) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah... I don't like those things that look like proc calls syntactically but then stuff a return into the code. It makes things very hard to read. It makes things look more like exception-based code (i.e. a tad cleaner), but it's surprising behavior when using result types IMHO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you really want to do something like that, it has to at least look like an explicit return IMHO. Something like:
returnOnFail c.next()and then have returnOnFail as your template.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have removed this template and replaced with ? template.
serde/cbor/deserializer.nim
Outdated
|
|
||
| func arrayLen*(c: CborParser): int = | ||
| ## Return the length of the array that the parser is positioned on. | ||
| assert(c.kind == CborEventKind.cborArray, $c.kind) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did you decide to throw an exception here instead of using result as you did with bytesLen? Also, I don't see this proc being used anywhere (nor bytestLen)?
serde/cbor/jsonhook.nim
Outdated
| import ./errors | ||
| import ./deserializer | ||
|
|
||
| proc toJsonHook*(n: CborNode): JsonNode = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd call this toJson and keep it uniform with nim-serde API.
serde/cbor/serializer.nim
Outdated
| except Exception as e: | ||
| return failure(e.msg) | ||
|
|
||
| proc writeCborHook*(str: Stream; dt: DateTime): ?!void = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would probably rename all of those to toCbor.
| func keysNotIn[T](json: JsonNode, obj: T): HashSet[string] = | ||
| let jsonKeys = json.keys.toSeq.toHashSet | ||
| let objKeys = obj.fieldKeys.toHashSet | ||
| difference(jsonKeys, objKeys) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wouldn't move those around for no reason. It's actually confusing cause I thought you were using them in the CBOR code, but then later realized you're not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gmega I've moved this to serde/json/helper.nim to separate helper functions from the core logic. This helps improve the overall structure and maintainability of the code
| import pkg/serde/cbor | ||
| import pkg/questionable | ||
| import pkg/questionable/results | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pretty awesome test!
gmega
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great job, I think this is much better now. I think the documentation still needs work to be easier to follow (I'm also not sure I'm so fond of the separate READMEs), but I don't have the time to work on it now. :-( Plus - all the info is there, so good enough for now I suppose.
README.md
Outdated
| ## Supported Wire Formats | ||
|
|
||
| Opt-in serialization by default: | ||
| nim-serde currently supports the following wire formats: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| nim-serde currently supports the following wire formats: | |
| nim-serde currently supports the following serialization formats: |
README.md
Outdated
| # nim-serde | ||
|
|
||
| Easy-to-use json serialization capabilities, and a drop-in replacement for `std/json`. | ||
| A serialization and deserialization library for Nim supporting multiple wire formats. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| A serialization and deserialization library for Nim supporting multiple wire formats. | |
| A serialization and deserialization library for Nim supporting multiple formats. |
I wouldn't say "wire" as those might well be serialized for other reasons, not just sending over the wire.
serde/cbor/README.md
Outdated
| let userCborData = userStream.data | ||
| ``` | ||
|
|
||
| ### Converting to CBOR with `toCbor` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean this is good enough as all the info needed to use the library is here. However: I'd probably use this as the initial example as it's the simplest API, and it's also what looks the most like the JSON API. Would then talk about the streaming API as a more advanced, CBOR-only feature and, finally, about working with CBOR node.
serde/cbor/README.md
Outdated
|
|
||
| The nim-serde CBOR serialization API provides several ways to convert Nim values to CBOR. | ||
|
|
||
| ### Basic Serialization with Stream API |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| ### Basic Serialization with Stream API | |
| ### Stream API: Primitive Type and Sequence Serialization |
serde/json/README.md
Outdated
| let jsonObj = %*{ | ||
| "name": "John", | ||
| "age": 30, | ||
| "hobbies": ["reading", "coding"], | ||
| "address": { | ||
| "street": "123 Main St", | ||
| "city": "Anytown" | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| let jsonObj = %*{ | |
| "name": "John", | |
| "age": 30, | |
| "hobbies": ["reading", "coding"], | |
| "address": { | |
| "street": "123 Main St", | |
| "city": "Anytown" | |
| } | |
| } | |
| let | |
| age = 30 | |
| name = "John" | |
| jsonObj = %*{ | |
| "name": name, | |
| "age": age, | |
| "hobbies": ["reading", "coding"], | |
| "address": { | |
| "street": "123 Main St", | |
| "city": "Anytown" | |
| } | |
| } |
gmega
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think the examples in the detailed docs are a bit confusing and suggested some edits, but I guess we're getting to diminishing returns on review rounds. Since @emizzle also thinks this is good enough, I'm comfortable approving it.
Co-authored-by: Giuliano Mega <[email protected]>
This PR introduces support for canonical CBOR serialization in compliance with RFC 8949.
Note that this implementation does not yet support serde features such as
OptIn, OptOut, Strict, or serialize/deserializepragma annotations