2020-12-30 15:43:18 +00:00
|
|
|
#lang racket
|
|
|
|
;; Jelly, a very shaky implementation of Preserves - intended to
|
|
|
|
;; demonstrate a minimal implementation of Preserves binary I/O,
|
|
|
|
;; without error-checking or configurability etc.
|
|
|
|
|
|
|
|
(provide (all-defined-out))
|
|
|
|
|
|
|
|
;;---------------------------------------------------------------------------
|
|
|
|
;; Representing values
|
|
|
|
|
2022-11-06 21:27:01 +00:00
|
|
|
(require "float.rkt" "float-bytes.rkt")
|
2020-12-30 15:43:18 +00:00
|
|
|
(struct record (label fields) #:transparent)
|
|
|
|
(struct annotated (annotations item) #:transparent)
|
2021-05-17 12:54:06 +00:00
|
|
|
(struct embedded (value) #:transparent)
|
2020-12-30 15:43:18 +00:00
|
|
|
|
|
|
|
;;---------------------------------------------------------------------------
|
|
|
|
;; Reader
|
|
|
|
|
|
|
|
(define (read-preserve/binary [in-port (current-input-port)])
|
|
|
|
(let/ec return
|
|
|
|
|
|
|
|
(define (next)
|
|
|
|
(match (next-byte)
|
|
|
|
[#x80 #f]
|
|
|
|
[#x81 #t]
|
2022-11-06 21:27:01 +00:00
|
|
|
[#x82 (bytes->float (next-bytes 4))]
|
|
|
|
[#x83 (bytes->double (next-bytes 8))]
|
2020-12-30 15:43:18 +00:00
|
|
|
[#x84 '#:end]
|
|
|
|
[#x85 (let ((a (next)))
|
|
|
|
(match (next)
|
|
|
|
[(annotated as i) (annotated (cons a as) i)]
|
|
|
|
[i (annotated (list a) i)]))]
|
2021-05-17 12:54:06 +00:00
|
|
|
[#x86 (embedded (next))]
|
2020-12-30 15:43:18 +00:00
|
|
|
[(? (between #x90 #x9C) v) (- v #x90)]
|
|
|
|
[(? (between #x9D #x9F) v) (- v #xA0)]
|
|
|
|
[(? (between #xA0 #xAF) v) (next-integer (- v #xA0 -1))]
|
|
|
|
[#xB0 (next-integer (next-varint))]
|
|
|
|
[#xB1 (bytes->string/utf-8 (next-bytes (next-varint)))]
|
|
|
|
[#xB2 (next-bytes (next-varint))]
|
|
|
|
[#xB3 (string->symbol (bytes->string/utf-8 (next-bytes (next-varint))))]
|
|
|
|
[#xB4 (apply (lambda (label . fields) (record label fields)) (next-items))]
|
|
|
|
[#xB5 (next-items)]
|
|
|
|
[#xB6 (list->set (next-items))]
|
|
|
|
[#xB7 (apply hash (next-items))]))
|
|
|
|
|
|
|
|
(define (next-items) (match (next) ['#:end '()] [v (cons v (next-items))]))
|
|
|
|
|
|
|
|
(define (eof-guard v) (if (eof-object? v) (return eof) v))
|
|
|
|
|
|
|
|
(define (next-byte) (eof-guard (read-byte in-port)))
|
|
|
|
|
|
|
|
(define (next-bytes n)
|
|
|
|
(define bs (eof-guard (read-bytes n in-port)))
|
|
|
|
(if (< (bytes-length bs) n) (return eof) bs))
|
|
|
|
|
|
|
|
(define (next-varint) (eof-guard (read-varint in-port)))
|
|
|
|
|
|
|
|
(define (next-integer n)
|
|
|
|
(define acc0 (next-byte))
|
|
|
|
(define acc (if (< acc0 128) acc0 (- acc0 256)))
|
|
|
|
(for/fold [(acc acc)] [(n (in-range (- n 1)))] (+ (* acc 256) (next-byte))))
|
|
|
|
|
|
|
|
(next)))
|
|
|
|
|
|
|
|
(define ((between lo hi) v) (<= lo v hi))
|
|
|
|
|
|
|
|
(define (read-varint in-port)
|
|
|
|
(let/ec return
|
|
|
|
(let loop ()
|
|
|
|
(define b (read-byte in-port))
|
|
|
|
(cond [(eof-object? b) (return b)]
|
|
|
|
[(< b 128) b]
|
|
|
|
[else (+ (* (loop) 128) (- b 128))]))))
|
|
|
|
|
|
|
|
;;---------------------------------------------------------------------------
|
|
|
|
;; Writer
|
|
|
|
|
|
|
|
(define (write-preserve/binary v [out-port (current-output-port)])
|
|
|
|
(define (output v)
|
|
|
|
(match v
|
|
|
|
[#f (write-byte #x80 out-port)]
|
|
|
|
[#t (write-byte #x81 out-port)]
|
2022-11-06 21:27:01 +00:00
|
|
|
[(float _) (write-byte #x82 out-port) (output-bytes (float->bytes v))]
|
|
|
|
[(? flonum?) (write-byte #x83 out-port) (output-bytes (double->bytes v))]
|
2020-12-30 15:43:18 +00:00
|
|
|
|
|
|
|
[(annotated as v)
|
|
|
|
(for [(a (in-list as))] (write-byte #x85 out-port) (output a))
|
|
|
|
(output v)]
|
|
|
|
|
2021-05-17 12:54:06 +00:00
|
|
|
[(embedded v) (write-byte #x86 out-port) (output v)]
|
2021-01-29 11:03:28 +00:00
|
|
|
|
2020-12-30 15:43:18 +00:00
|
|
|
[(? integer?)
|
|
|
|
(cond [(<= -3 v -1) (write-byte (+ v #xA0) out-port)]
|
|
|
|
[(<= 0 v 12) (write-byte (+ v #x90) out-port)]
|
|
|
|
[else (define raw-bit-count (+ (integer-length v) 1)) ;; at least one sign bit
|
|
|
|
(define byte-count (quotient (+ raw-bit-count 7) 8))
|
|
|
|
(if (<= byte-count 16)
|
|
|
|
(write-byte (+ byte-count #xA0 -1) out-port)
|
|
|
|
(begin (write-byte #xB0 out-port)
|
|
|
|
(write-varint byte-count out-port)))
|
|
|
|
(for [(shift (in-range (* byte-count 8) 0 -8))]
|
|
|
|
(write-byte (bitwise-bit-field v (- shift 8) shift) out-port))])]
|
|
|
|
|
|
|
|
[(? string?) (count-bytes 1 (string->bytes/utf-8 v))]
|
|
|
|
[(? bytes?) (count-bytes 2 v)]
|
|
|
|
[(? symbol?) (count-bytes 3 (string->bytes/utf-8 (symbol->string v)))]
|
|
|
|
|
|
|
|
[(record label fields) (with-seq 4 (output label) (for-each output fields))]
|
|
|
|
[(? list?) (with-seq 5 (for-each output v))]
|
|
|
|
[(? set?) (with-seq 6 (output-set v))]
|
|
|
|
[(? hash?) (with-seq 7 (output-hash v))]
|
|
|
|
|
|
|
|
[_ (error 'write-preserve/binary "Invalid value: ~v" v)]))
|
|
|
|
|
|
|
|
(define (output-bytes bs) (write-bytes bs out-port))
|
|
|
|
|
|
|
|
(define-syntax-rule (with-seq tag body ...)
|
|
|
|
(begin (write-byte (+ tag #xB0) out-port)
|
|
|
|
body ...
|
|
|
|
(write-byte #x84 out-port)))
|
|
|
|
|
|
|
|
(define (count-bytes tag bs)
|
|
|
|
(write-byte (+ tag #xB0) out-port)
|
|
|
|
(write-varint (bytes-length bs) out-port)
|
|
|
|
(output-bytes bs))
|
|
|
|
|
|
|
|
(define (encode v) (call-with-output-bytes (lambda (p) (write-preserve/binary v p))))
|
|
|
|
|
|
|
|
(define (output-set v)
|
|
|
|
(for-each output-bytes (sort (for/list [(e (in-set v))] (encode e)) bytes<?)))
|
|
|
|
|
|
|
|
(define (output-hash d)
|
|
|
|
(define encoded-entries (for/list [((k v) (in-hash d))] (cons (encode k) (encode v))))
|
|
|
|
(for-each output-bytes (flatten (sort encoded-entries bytes<? #:key car))))
|
|
|
|
|
|
|
|
(output v))
|
|
|
|
|
|
|
|
(define (write-varint v out-port)
|
|
|
|
(if (< v 128)
|
|
|
|
(write-byte v out-port)
|
|
|
|
(begin (write-byte (+ 128 (modulo v 128)) out-port)
|
|
|
|
(write-varint (quotient v 128) out-port))))
|