tangled
alpha
login
or
join now
8bit.lol
/
pegasus
forked from
futur.blue/pegasus
0
fork
atom
objective categorical abstract machine language personal data server
0
fork
atom
overview
issues
pulls
pipelines
DAG-CBOR to/of yojson
futur.blue
7 months ago
116aafe3
04c19333
verified
This commit was signed with the committer's
known signature
.
futur.blue
SSH Key Fingerprint:
SHA256:QHGqHWNpqYyw9bt8KmPuJIyeZX9SZewBZ0PR1COtKQ0=
+109
-6
6 changed files
expand all
collapse all
unified
split
dune-project
ipld
lib
dag_cbor.ml
dune
test
dune
test_dag_cbor.ml
ipld.opam
+2
dune-project
···
43
43
(depends
44
44
ocaml
45
45
dune
46
46
+
(base64 (>= 3.5.1))
46
47
(digestif (>= 1.2.0))
47
48
(multibase (>= 0.1.0))
49
49
+
(yojson (>= 3.0.0))
48
50
(alcotest :with-test)))
+2
ipld.opam
···
10
10
depends: [
11
11
"ocaml"
12
12
"dune" {>= "3.14"}
13
13
+
"base64" {>= "3.5.1"}
13
14
"digestif" {>= "1.2.0"}
14
15
"multibase" {>= "0.1.0"}
16
16
+
"yojson" {>= "3.0.0"}
15
17
"alcotest" {with-test}
16
18
"odoc" {with-doc}
17
19
]
+58
ipld/lib/dag_cbor.ml
···
27
27
| `Map of value StringMap.t
28
28
| `Link of Cid.t ]
29
29
30
30
+
let rec of_yojson (json : Yojson.Safe.t) : value =
31
31
+
match json with
32
32
+
| `Assoc [("$bytes", `String s)] ->
33
33
+
`Bytes (Bytes.of_string (Base64.decode_exn s))
34
34
+
| `Assoc [("$link", `String s)] ->
35
35
+
`Link (Result.get_ok (Cid.of_string s))
36
36
+
| `Assoc assoc_list ->
37
37
+
`Map
38
38
+
(StringMap.of_list
39
39
+
(List.map (fun (k, v) -> (k, of_yojson v)) assoc_list) )
40
40
+
| `List lst ->
41
41
+
`Array (Array.of_list (List.map of_yojson lst))
42
42
+
| `Bool b ->
43
43
+
`Boolean b
44
44
+
| `Int i ->
45
45
+
`Integer (Int64.of_int i)
46
46
+
| `Intlit s ->
47
47
+
`Integer (Int64.of_string s)
48
48
+
| `Float f ->
49
49
+
`Float f
50
50
+
| `String s ->
51
51
+
`String s
52
52
+
| `Null ->
53
53
+
`Null
54
54
+
55
55
+
let rec to_yojson (value : value) : Yojson.Safe.t =
56
56
+
match value with
57
57
+
| `Map map ->
58
58
+
`Assoc (StringMap.to_list map |> List.map (fun (k, v) -> (k, to_yojson v)))
59
59
+
| `Array arr ->
60
60
+
`List (Array.to_list arr |> List.map to_yojson)
61
61
+
| `Bytes bytes ->
62
62
+
`Assoc
63
63
+
[ ( "$bytes"
64
64
+
, `String (Base64.encode_exn ~pad:false (Bytes.to_string bytes)) ) ]
65
65
+
| `Link cid ->
66
66
+
`Assoc [("$link", `String (Cid.to_string cid))]
67
67
+
| `Boolean b ->
68
68
+
`Bool b
69
69
+
| `Integer i ->
70
70
+
`Intlit (Int64.to_string i)
71
71
+
| `Float f ->
72
72
+
`Float f
73
73
+
| `String s ->
74
74
+
`String s
75
75
+
| `Null ->
76
76
+
`Null
77
77
+
30
78
module Encoder = struct
31
79
type t = {mutable buf: Buffer.t; mutable pos: int}
32
80
···
159
207
if encoder.pos < Buffer.length encoder.buf then
160
208
Buffer.truncate encoder.buf encoder.pos ;
161
209
Buffer.to_bytes encoder.buf
210
210
+
211
211
+
let encode_yojson (v : Yojson.Safe.t) : bytes = of_yojson v |> encode
162
212
end
163
213
164
214
module Decoder = struct
···
357
407
(Printf.sprintf "decode: extra bytes after valid CBOR data (%d)"
358
408
(Bytes.length remainder) ) ;
359
409
value
410
410
+
411
411
+
let decode_to_yojson buf =
412
412
+
let value = decode buf in
413
413
+
to_yojson value
360
414
end
361
415
362
416
let encode = Encoder.encode
363
417
364
418
let decode = Decoder.decode
419
419
+
420
420
+
let encode_yojson = Encoder.encode_yojson
421
421
+
422
422
+
let decode_to_yojson = Decoder.decode_to_yojson
+1
-1
ipld/lib/dune
···
1
1
(library
2
2
(name ipld)
3
3
(wrapped false)
4
4
-
(libraries digestif multibase))
4
4
+
(libraries base64 digestif multibase yojson))
+1
-1
ipld/test/dune
···
1
1
(tests
2
2
(names test_cid test_dag_cbor)
3
3
(package ipld)
4
4
-
(libraries ipld alcotest))
4
4
+
(libraries ipld str alcotest))
+45
-4
ipld/test/test_dag_cbor.ml
···
3
3
let rec stringify_map m =
4
4
StringMap.bindings m
5
5
|> List.map (fun (k, v) ->
6
6
-
Format.sprintf "%s: %s" k (stringify_ipld_value v) )
7
7
-
|> String.concat ", " |> Format.sprintf "{ %s }"
6
6
+
Format.sprintf "\"%s\": %s" k (stringify_ipld_value v) )
7
7
+
|> String.concat ", " |> Format.sprintf "{%s}"
8
8
9
9
and stringify_ipld_value (value : Dag_cbor.value) =
10
10
match value with
···
15
15
| `Float f ->
16
16
Format.sprintf "%f" f
17
17
| `String s ->
18
18
-
Format.sprintf "\"%s\"" s
18
18
+
Format.sprintf "\"%s\""
19
19
+
(Str.global_replace (Str.regexp_string {|"|}) {|\"|} s)
19
20
| `Bytes b ->
20
21
Format.sprintf "%s" (Bytes.to_string b)
21
22
| `Map m ->
···
58
59
false
59
60
60
61
let ipld_testable = Alcotest.testable pprint_ipld_value ipld_value_eq
62
62
+
63
63
+
let yojson_testable = Alcotest.testable Yojson.Safe.pp Yojson.Safe.equal
61
64
62
65
let to_base_16 bytes =
63
66
let hex_of_nibble n =
···
383
386
Alcotest.(check bool) "second object decoded correctly" true (decoded2 = obj2) ;
384
387
Alcotest.(check int) "no remaining bytes" 0 (Bytes.length final_remainder)
385
388
389
389
+
let test_yojson_roundtrip () =
390
390
+
let record_embed_images_0_aspect_ratio : Yojson.Safe.t =
391
391
+
`Assoc [("height", `Intlit "885"); ("width", `Intlit "665")]
392
392
+
in
393
393
+
let record_embed_images_0_image : Yojson.Safe.t =
394
394
+
`Assoc
395
395
+
[ ("height", `Intlit "885")
396
396
+
; ("width", `Intlit "665")
397
397
+
; ("mimeType", `String "image/jpeg")
398
398
+
; ("size", `Intlit "645553") ]
399
399
+
in
400
400
+
let record_embed_images_0 : Yojson.Safe.t =
401
401
+
`Assoc
402
402
+
[ ( "alt"
403
403
+
, `String
404
404
+
"a photoshopped picture of kit with a microphone. kit is saying \
405
405
+
\"meow\"" )
406
406
+
; ("aspectRatio", record_embed_images_0_aspect_ratio)
407
407
+
; ("image", record_embed_images_0_image) ]
408
408
+
in
409
409
+
let record_embed : Yojson.Safe.t =
410
410
+
`Assoc
411
411
+
[ ("$type", `String "app.bsky.embed.images")
412
412
+
; ("images", `List [record_embed_images_0]) ]
413
413
+
in
414
414
+
let record : Yojson.Safe.t =
415
415
+
`Assoc
416
416
+
[ ("$type", `String "app.bsky.feed.post")
417
417
+
; ("createdAt", `String "2024-08-13T01:16:06.453Z")
418
418
+
; ("langs", `List [`String "en"])
419
419
+
; ("text", `String "exclusively on bluesky")
420
420
+
; ("embed", record_embed) ]
421
421
+
in
422
422
+
let encoded = Dag_cbor.encode_yojson record in
423
423
+
let decoded = Dag_cbor.decode_to_yojson encoded in
424
424
+
Alcotest.(check yojson_testable) "yojson roundtrip" record decoded
425
425
+
386
426
let () =
387
427
Alcotest.run "dag-cbor"
388
428
[ ( "dag-cbor encoding"
···
390
430
; ("round_trip", `Quick, test_round_trip)
391
431
; ("atproto_records", `Quick, test_atproto_post_records)
392
432
; ("invalid_numbers", `Quick, test_invalid_numbers)
393
393
-
; ("decode_multiple", `Quick, test_decode_multiple_objects) ] ) ]
433
433
+
; ("decode_multiple", `Quick, test_decode_multiple_objects)
434
434
+
; ("yojson_roundtrip", `Quick, test_yojson_roundtrip) ] ) ]