Emily Martins: 1 implement sorting on map keys 6 files changed, 70 insertions(+), 8 deletions(-)
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~williewillus/racket-libraries/patches/40187/mbox | git am -3Learn more about email & git
Hi Vincent, Here's a patch for allowing the sorting of map keys when encoding cbor values. I thought about extending the functionality to allow arbitrary sorting. But for now, this works quite well for such a niche use-case. I'd be willing to help maintain this package as it's something I have to use quite frequently in various of the projects I'm involved with. If you'd prefer, I'm available to talk on Discord too. Regards, emi --- common.rkt | 12 ++++++++++-- encode.rkt | 12 +++++++++--- flake.lock | 25 +++++++++++++++++++++++++ flake.nix | 15 +++++++++++++++ info.rkt | 2 +- scribblings/manual.scrbl | 12 ++++++++++-- 6 files changed, 70 insertions(+), 8 deletions(-) create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/common.rkt b/common.rkt index 979fb0a..79f9370 100644 --- a/common.rkt +++ b/common.rkt @@ -31,9 +31,11 @@ (provide cbor-config? cbor-config-tag-deserializers cbor-config-null-value + cbor-config-sorted-map-keys (contract-out [cbor-empty-config cbor-config?] [with-cbor-null (-> cbor-config? any/c cbor-config?)] + [with-sorted-map-keys (-> cbor-config? boolean? cbor-config?)] [with-cbor-tag-deserializer (-> cbor-config? cbor-valid-tag-number? (-> cbor-valid-tag-number? any/c any/c) @@ -41,9 +43,10 @@ (struct cbor-config (tag-deserializers - null-value)) + null-value + sorted-map-keys)) -(define cbor-empty-config (cbor-config #hasheqv() 'null)) +(define cbor-empty-config (cbor-config #hasheqv() 'null #f)) (define (with-cbor-tag-deserializer config id deser) (define old-handlers (cbor-config-tag-deserializers config)) @@ -55,3 +58,8 @@ (struct-copy cbor-config config [null-value v])) + +(define (with-sorted-map-keys config sorted) + (struct-copy + cbor-config config + [sorted-map-keys sorted])) diff --git a/encode.rkt b/encode.rkt index 4439a73..b9a09a6 100644 --- a/encode.rkt +++ b/encode.rkt @@ -3,6 +3,7 @@ (require racket/generic racket/undefined "common.rkt") +(require racket/match) (provide cbor-write gen:cbor-custom-write cbor-custom-write? @@ -93,9 +94,14 @@ (define (cbor-write-map config m out) (define len (hash-count m)) (write-argument out 5 len) - (hash-for-each m (lambda (k v) - (cbor-write config k out) - (cbor-write config v out))) + (if (cbor-config-sorted-map-keys config) + (for-each (match-lambda + [(cons k v) + (cbor-write config k out) + (cbor-write config v out)]) (sort (hash->list m) < #:key car)) + (hash-for-each m (lambda (k v) + (cbor-write config k out) + (cbor-write config v out)))) (when (> len u64-max) (write-break out))) diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..41767a0 --- /dev/null +++ b/flake.lock @@ -0,0 +1,25 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1680668850, + "narHash": "sha256-mQMg13yRsS0LXVzaeoSPwqgPO6yhkGzGewPgMSqXSv8=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "4a65e9f64e53fdca6eed31adba836717a11247d2", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "type": "indirect" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..0985146 --- /dev/null +++ b/flake.nix @@ -0,0 +1,15 @@ +{ + description = "Racket exploration env"; + + outputs = { self, nixpkgs }: + let + pkgs = import nixpkgs { system = "x86_64-linux"; }; + in + { + devShell.x86_64-linux = pkgs.mkShell { + buildInputs = [ + pkgs.racket + ]; + }; + }; +} diff --git a/info.rkt b/info.rkt index 3b94a5c..21104fa 100644 --- a/info.rkt +++ b/info.rkt @@ -1,6 +1,6 @@ #lang info (define collection "cbor") -(define version "0.9") +(define version "0.10") (define deps '("base")) (define build-deps '("racket-doc" "rackunit-lib" diff --git a/scribblings/manual.scrbl b/scribblings/manual.scrbl index 21e0047..0009606 100644 --- a/scribblings/manual.scrbl +++ b/scribblings/manual.scrbl @@ -55,12 +55,14 @@ Major types are decoded as follows: } @section{Configuration Options} -@defstruct[cbor-config ((tag-deserializers (hash/c cbor-valid-tag-number? (-> cbor-valid-tag-number? any/c any/c))) (null-value any/c))]{ +@defstruct[cbor-config ((tag-deserializers (hash/c cbor-valid-tag-number? (-> cbor-valid-tag-number? any/c any/c))) (null-value any/c) (sorted-map-keys boolean?))]{ Configuration object for CBOR encoding and decoding. Note that this struct is only exposed opaquely, and must be manipulated with the provided functions and values. @racket[tag-deserializers] is a hash from CBOR tag numbers to a procedure that takes the CBOR tag number and a raw data value and produces the meaningful interpretation of that value. @racket[null-value] is the value that CBOR @tt{null} will be encoded and decoded as. + +@racket[sorted-map-keys] determines whether or not map keys should appear in sorted order. This only affects encoding; unsorted map keys will still be parsed identically. Keep in mind, this functionality should not be depended on by any decoders, but for legacy purposes some decoders don't parse properly otherwise. } @defthing[cbor-empty-config cbor-config?]{ @@ -80,6 +82,12 @@ Registers a tag deserializer to the given config, returning a new config. Registers a null value to the given config, returning a new config. } +@defproc[(with-sorted-map-keys [config cbor-config?] + [v boolean?]) + cbor-config?]{ +Set whether map keys should be sorted. +} + @defthing[gen:cbor-custom-write any/c]{ A @tech{generic interface} that supplies a method, @racket[cbor-write-proc] that can serialize arbitrary values to CBOR. Implementations of the method should accept a value to be serialized and return it in serialized form as a @racket[cbor-tag?]. } @@ -113,4 +121,4 @@ Patches to improve these issues are welcome! Email patches to @tt{~williewillus/ @item{There should be a config or parameter to specify maximum lengths for indefinite-length objects} @item{More correctness-testing is needed.} @item{Some recommended tag and simple values from the RFC are not supported yet.} -] \ No newline at end of file +] -- 2.36.2