{"id":20780763,"url":"https://github.com/greglook/clj-cbor","last_synced_at":"2025-10-17T14:33:11.653Z","repository":{"id":44948316,"uuid":"70426513","full_name":"greglook/clj-cbor","owner":"greglook","description":"Native Clojure CBOR codec implementation.","archived":false,"fork":false,"pushed_at":"2022-06-20T18:15:41.000Z","size":482,"stargazers_count":70,"open_issues_count":2,"forks_count":7,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-04-22T11:44:32.975Z","etag":null,"topics":["binary-format","cbor","codec"],"latest_commit_sha":null,"homepage":null,"language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/greglook.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-10-09T19:48:00.000Z","updated_at":"2024-05-19T16:02:29.000Z","dependencies_parsed_at":"2022-08-25T10:31:01.885Z","dependency_job_id":null,"html_url":"https://github.com/greglook/clj-cbor","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greglook%2Fclj-cbor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greglook%2Fclj-cbor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greglook%2Fclj-cbor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greglook%2Fclj-cbor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/greglook","download_url":"https://codeload.github.com/greglook/clj-cbor/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253149965,"owners_count":21861803,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["binary-format","cbor","codec"],"created_at":"2024-11-17T13:39:07.030Z","updated_at":"2025-10-17T14:33:11.557Z","avatar_url":"https://github.com/greglook.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"clj-cbor\n========\n\n[![CircleCI](https://circleci.com/gh/greglook/clj-cbor.svg?style=shield\u0026circle-token=21efcbc50fe431aa2efc22413ba1f4407fec6283)](https://circleci.com/gh/greglook/clj-cbor)\n[![codecov](https://codecov.io/gh/greglook/clj-cbor/branch/main/graph/badge.svg)](https://codecov.io/gh/greglook/clj-cbor)\n[![cljdoc](https://cljdoc.org/badge/mvxcvi/clj-cbor)](https://cljdoc.org/d/mvxcvi/clj-cbor/CURRENT)\n\nThis library is a native Clojure implementation of the [Concise Binary Object Representation](http://cbor.io/)\nformat specified in [RFC 7049](https://tools.ietf.org/html/rfc7049).\n\nCBOR is a binary encoding with the goal of small code size, compact messages,\nand extensibility without the need for version negotiation. This makes it a good\nalternative to [EDN](https://github.com/edn-format/edn) for storing and\ntransmitting Clojure data in a more compact form.\n\n\n## Installation\n\nLibrary releases are published on Clojars. To use the latest version with\nLeiningen, add the following dependency to your project definition:\n\n[![Clojars Project](http://clojars.org/mvxcvi/clj-cbor/latest-version.svg)](http://clojars.org/mvxcvi/clj-cbor)\n\n\n## Usage\n\nThe `clj-cbor.core` namespace contains the high-level encoding and decoding\nfunctions. The simplest way to use this library is to require it and call them\ndirectly with data:\n\n```clojure\n=\u003e (require '[clj-cbor.core :as cbor])\n\n=\u003e (cbor/encode [0 :foo/bar true {:x 'y} #{1/3} #\"foo\"])\n; 0x8600D827683A666F6F2F626172F5A1D827623A78D8276179CD81D81E820103D82363666F6F\n\n=\u003e (cbor/decode *1)\n[0 :foo/bar true {:x y} #{1/3} #\"foo\"]\n```\n\nWith no extra arguments, `encode` and `decode` will make use of the\n`default-codec`, which comes loaded with read and write handler support for many\nJava and Clojure types (see the [type extensions](#type-extensions) section\nbelow). Both functions accept an additional argument to specify the codec,\nshould different behavior be desired.\n\n```clojure\n=\u003e (def codec (cbor/cbor-codec :canonical true))\n\n=\u003e (cbor/encode codec {:foo \"bar\", :baz 123})\n; 0xA2D827643A666F6F63626172D827643A62617A187B\n\n=\u003e (cbor/decode codec *1)\n{:foo \"bar\", :baz 123}\n```\n\nSo far we haven't specified any outputs when encoding, so we've gotten a byte\narray back. The full form of `encode` takes three arguments: the codec, the\noutput stream, and the value to encode.\n\n```clojure\n=\u003e (def out (java.io.ByteArrayOutputStream.))\n\n=\u003e (cbor/encode codec out :a)\n5\n\n=\u003e (cbor/encode codec out 123)\n2\n\n=\u003e (cbor/encode codec out true)\n1\n\n=\u003e (cbor/encode codec out \"foo\")\n4\n\n=\u003e (.toByteArray out))\n; 0xD827623A61187BF563666F6F\n\n=\u003e (with-open [input (java.io.ByteArrayInputStream. *1)]\n     (doall (cbor/decode-seq codec input)))\n(:a 123 true \"foo\")\n```\n\nIn this mode, `encode` returns the number of bytes written instead of a byte\narray. We can read multiple items from an input stream using `decode-seq`, which\nreturns a lazy sequence. If the input is a file you must realize the values\nbefore closing the input. Similarly, `encode-seq` will write a sequence of\nmultiple values to an output stream.\n\nAs a convenience, the library also provides the `spit`, `spit-all`, `slurp`, and\n`slurp-all` functions, which operate on files:\n\n```clojure\n=\u003e (cbor/spit \"data.cbor\" {:abc 123, :foo \"qux\", :bar true})\n29\n\n=\u003e (cbor/spit-all \"data.cbor\" [[0.0 'x] #{-42}] :append true)\n12\n\n=\u003e (.length (io/file \"data.cbor\"))\n41\n\n=\u003e (cbor/slurp \"data.cbor\")\n{:abc 123, :bar true, :foo \"qux\"}\n\n=\u003e (cbor/slurp-all \"data.cbor\")\n({:abc 123, :bar true, :foo \"qux\"} [0.0 x] #{-42})\n```\n\n\n## Type Extensions\n\nIn order to support types of values outside the ones which are a native to CBOR,\nthe format uses _tagged values_, similar to EDN. In CBOR, the tags are integer\nnumbers instead of symbols, but the purpose is the same: the tags convey _new\nsemantics_ about the following value.\n\nThe most common example of a need for this kind of type extension is\nrepresenting an instant in time. In EDN, this is represented by the `#inst` tag\non an ISO-8601 timestamp string. CBOR offers two tags to represent instants -\ntag 0 codes a timestamp string, while tag 1 codes a number in epoch seconds. The\nformer is more human-friendly, but the latter is more efficient.\n\nNew types are implemented by using read and write handlers - functions which map\nfrom typed value to representation and back. Currently, the library comes with\nsupport for the following types:\n\n|   Tag | Representation | Type | Semantics |\n|-------|----------------|------|-----------|\n|     0 | Text string    | `Date`/`Instant` | Standard date/time string |\n|     1 | Number         | `Date`/`Instant` | Epoch-based date/time |\n|     2 | Byte string    | `BigInt` | Positive bignum |\n|     3 | Byte string    | `BigInt` | Negative bignum |\n|     4 | Array(2)       | `BigDecimal` | Decimal fraction |\n|    27 | Array(2)       | `TaggedLiteral` | Constructor support for Clojure tagged literal values |\n|    30 | Array(2)       | `Ratio` | Rational fractions, represented as numerator and denominator numbers |\n|    32 | Text string    | `URI` | Uniform Resource Identifier strings |\n|    35 | Text string    | `Pattern` | Regular expression strings |\n|    37 | Byte string    | `UUID` | Binary-encoded UUID values |\n|    39 | Text string    | `Symbol`/`Keyword` | Identifiers |\n|   100 | Integer        | `LocalDate` | Epoch-based local calendar date |\n|   258 | Array          | `Set` | Sets of unique entries |\n|  1004 | Text string    | `LocalDate` | String-based local calendar date |\n| 55799 | Varies         | N/A | Self-describe CBOR |\n\nFor further information about registered tag semantics, consult the\n[IANA Registry](https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml).\n\n### Write Handlers\n\nA write handler is a function which takes a typed value and returns an\nencodable representation. In most cases, the representation is a CBOR tagged\nvalue. The tag conveys the type semantic and generally the expected form that\nthe representation takes. Write handlers are selected by a dispatch function,\nwhich defaults to `class`. The `clj-cbor.core/dispatch-superclasses` function\ncan be used to construct an inheritance-based dispatcher.\n\nIn some cases, multiple types will map to the same tag. For example, by default\nthis library maps both `java.util.Date` and the newer `java.time.Instant` types\nto the same representation.\n\n### Read Handlers\n\nA read handler is a function which takes the representation from a tagged value\nand returns an appropriately typed value. The choice of function to parse the\nvalues thus determines the 'preferred type' to represent values of that kind.\n\nContinuing the example, the library comes with read handlers for both `Date` and\n`Instant` types, allowing the user to choose their preferred time type.\n\n\n## Performance\n\nAs of `0.7.1`, this library is competitive with many other comparable\nserialization formats. Some benchmarking results can be found in\n[this spreadsheet](https://docs.google.com/spreadsheets/d/142LhWX5aCnOoF6v0T46RASULQDuG7JIckKiCohDPgq8/edit?usp=sharing).\n\nFor small and medium data sizes CBOR is more compact than most formats, while at\nlarger sizes (above 512 bytes) all formats are fairly close in size (within 10%,\ngenerally). Other than Nippy, which was by far the fastest codec, clj-cbor\nwas one of the fastest encoders and is in the middle of the pack in decoding\ntimes.\n\nTo give some concrete performance numbers, here are a few samples from the\ndataset:\n\n| Size |    Encode |    Decode |\n|------|-----------|-----------|\n|    4 |   6.09 µs |   2.31 µs |\n|   55 |  20.87 µs |   7.58 µs |\n|  173 |  12.64 µs |   5.74 µs |\n|  388 |  15.38 µs |  11.60 µs |\n|  882 |  31.55 µs |  14.24 µs |\n| 1632 |  54.82 µs |  33.52 µs |\n| 3127 |  92.14 µs |  64.66 µs |\n| 4918 | 104.92 µs |  59.67 µs |\n| 7328 | 108.37 µs |  82.16 µs |\n\n\n## Notes\n\nA few things to keep in mind while using the library:\n\n- Streaming CBOR data can be parsed from input, but there is currently no way to\n  generate streaming output data.\n- Decoding half-precision (16-bit) floating-point numbers is supported, but the\n  values are promoted to single-precision (32-bit) as the JVM does not have\n  native support for them. There is currently no support for writing\n  half-precision floats except for the special values `0.0`, `+Inf`, `-Inf`, and\n  `NaN`, which are always written as two bytes for efficiency.\n- CBOR does not have a type for bare characters, so they will be converted to\n  single-character strings when written.\n- Regular expressions are supported using tag 35, but beware that Java\n  `Pattern` objects do not compare equal or have the same hash code for\n  otherwise identical regexes. Using them in sets or as map keys is discouraged.\n\n\n## License\n\nThis is free and unencumbered software released into the public domain.\nSee the UNLICENSE file for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgreglook%2Fclj-cbor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgreglook%2Fclj-cbor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgreglook%2Fclj-cbor/lists"}