Skip to content

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

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open

feat: support for CBOR #32

wants to merge 17 commits into from

Conversation

munna0908
Copy link

@munna0908 munna0908 commented May 22, 2025

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/deserialize pragma annotations

@munna0908 munna0908 requested review from dryajov, gmega and emizzle May 22, 2025 11:20
@munna0908 munna0908 self-assigned this May 22, 2025
Copy link
Member

@gmega gmega left a 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:

  1. 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;
  2. 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.

return failure(e.msg)
except OSError as e:
return failure(e.msg)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change


?c.next()
return success(val)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

return failure(newCborError("Expected positive integer, got " & $c.kind))
let val = c.intVal.BiggestUInt

?c.next()
Copy link
Member

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.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gmega In my opinion, this is the cleanest way to handle the "return on failure" scenario.
Based on my discussions with @dryajov, we hadn't used this approach earlier because it didn't support Futures. Now that it does, we’ll be using this syntax more extensively

let n = c.s.readData(buf[0].addr, buf.len)
if n != buf.len:
return failure(newCborError("truncated read of CBOR data"))
tryNext(c)
Copy link
Member

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.

Copy link
Member

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.

Copy link
Author

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.


func arrayLen*(c: CborParser): int =
## Return the length of the array that the parser is positioned on.
assert(c.kind == CborEventKind.cborArray, $c.kind)
Copy link
Member

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)?

import ./errors
import ./deserializer

proc toJsonHook*(n: CborNode): JsonNode =
Copy link
Member

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.

except Exception as e:
return failure(e.msg)

proc writeCborHook*(str: Stream; dt: DateTime): ?!void =
Copy link
Member

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)
Copy link
Member

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.

Copy link
Author

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

check roundtrip.coordinates.x == original.coordinates.x
check roundtrip.coordinates.y == original.coordinates.y
check roundtrip.coordinates.label == original.coordinates.label

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

import pkg/serde/cbor
import pkg/questionable
import pkg/questionable/results

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty awesome test!

@munna0908 munna0908 marked this pull request as ready for review June 1, 2025 18:43
@munna0908 munna0908 requested a review from gmega June 1, 2025 18:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants