Skip to content

feat: support for CBOR#32

Open
munna0908 wants to merge 20 commits into
masterfrom
feat/cbor
Open

feat: support for CBOR#32
munna0908 wants to merge 20 commits into
masterfrom
feat/cbor

Conversation

@munna0908
Copy link
Copy Markdown

@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, emizzle and gmega May 22, 2025 11:20
@munna0908 munna0908 self-assigned this May 22, 2025
Copy link
Copy Markdown

@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.

Comment thread serde/cbor/deserializer.nim
Comment thread serde/cbor/deserializer.nim
Comment thread serde/cbor/deserializer.nim Outdated
return failure(newCborError("Expected positive integer, got " & $c.kind))
let val = c.intVal.BiggestUInt

?c.next()
Copy link
Copy Markdown

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
Copy Markdown
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

Comment thread 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)
Copy link
Copy Markdown

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
Copy Markdown

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
Copy Markdown
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.

Comment thread 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)
Copy link
Copy Markdown

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

Comment thread serde/cbor/jsonhook.nim Outdated
import ./errors
import ./deserializer

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

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.

Comment thread serde/cbor/serializer.nim Outdated
except Exception as e:
return failure(e.msg)

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

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
Copy Markdown

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
Copy Markdown
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

Comment thread tests/cbor/testObjects.nim
import pkg/serde/cbor
import pkg/questionable
import pkg/questionable/results

Copy link
Copy Markdown

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
Copy link
Copy Markdown

@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.

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.

Comment thread README.md Outdated
## Supported Wire Formats

Opt-in serialization by default:
nim-serde currently supports the following wire formats:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
nim-serde currently supports the following wire formats:
nim-serde currently supports the following serialization formats:

Comment thread 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.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
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.

Comment thread serde/cbor/README.md
Comment thread serde/cbor/README.md Outdated
let userCborData = userStream.data
```

### Converting to CBOR with `toCbor`
Copy link
Copy Markdown

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.

Comment thread 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
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
### Basic Serialization with Stream API
### Stream API: Primitive Type and Sequence Serialization

Comment thread serde/json/README.md Outdated
Comment on lines +77 to +85
let jsonObj = %*{
"name": "John",
"age": 30,
"hobbies": ["reading", "coding"],
"address": {
"street": "123 Main St",
"city": "Anytown"
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
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"
}
}

Comment thread serde/json/README.md
Comment thread serde/json/README.md
Comment thread serde/json/README.md Outdated
Comment thread serde/json/README.md
@munna0908 munna0908 requested a review from gmega June 9, 2025 07:59
Copy link
Copy Markdown

@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.

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.

Comment thread README.md Outdated
Comment thread README.md Outdated
Comment thread serde/json/README.md Outdated
Comment thread serde/json/README.md Outdated
Co-authored-by: Giuliano Mega <giuliano.mega@gmail.com>
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