68 lines
2.7 KiB
Racket
68 lines
2.7 KiB
Racket
#lang racket/base
|
|
|
|
(provide varint->iolist
|
|
write-varint
|
|
read-varint
|
|
encode-varint
|
|
decode-varint)
|
|
|
|
(require racket/port)
|
|
|
|
(define (varint->iolist n)
|
|
(let wr ((n n) (d 128))
|
|
(if (< n 128)
|
|
(+ d n)
|
|
(cons (wr (quotient n 128) 0) (+ d (modulo n 128))))))
|
|
|
|
(define (write-varint n out-port)
|
|
(let wr ((n n) (d 128))
|
|
(if (< n 128)
|
|
(write-byte (+ d n) out-port)
|
|
(begin (wr (quotient n 128) 0)
|
|
(write-byte (+ d (modulo n 128)) out-port)))))
|
|
|
|
(define (read-varint in-port [first-byte (read-byte in-port)])
|
|
(let rd ((acc 0) (b first-byte))
|
|
(cond [(eof-object? b) eof]
|
|
[(< b 128) (rd (+ (* acc 128) b) (read-byte in-port))]
|
|
[else (+ (* acc 128) (- b 128))])))
|
|
|
|
(define (encode-varint v)
|
|
(call-with-output-bytes (lambda (p) (write-varint v p))))
|
|
|
|
(define (decode-varint bs ks kf)
|
|
((call-with-input-bytes bs (lambda (p)
|
|
(define v (read-varint p))
|
|
(cond [(eof-object? v) (lambda () (kf #t))]
|
|
[else (define rest (port->bytes p))
|
|
(lambda () (ks v rest))])))))
|
|
|
|
(module+ test
|
|
(require rackunit)
|
|
|
|
(check-equal? (encode-varint 0) (bytes 128))
|
|
(check-equal? (encode-varint 1) (bytes 129))
|
|
(check-equal? (encode-varint 127) (bytes 255))
|
|
(check-equal? (encode-varint 128) (bytes 1 128))
|
|
(check-equal? (encode-varint 255) (bytes 1 255))
|
|
(check-equal? (encode-varint 256) (bytes 2 128))
|
|
(check-equal? (encode-varint 300) (bytes #b00000010 #b10101100))
|
|
(check-equal? (encode-varint 1000000000) (bytes 3 92 107 20 128))
|
|
|
|
(define (ks* v rest) (list v rest))
|
|
(define (kf* [short? #f]) (if short? 'short (void)))
|
|
|
|
(check-equal? (decode-varint (bytes) ks* kf*) 'short)
|
|
(check-equal? (decode-varint (bytes 128) ks* kf*) (list 0 (bytes)))
|
|
(check-equal? (decode-varint (bytes 128 99) ks* kf*) (list 0 (bytes 99)))
|
|
(check-equal? (decode-varint (bytes 129) ks* kf*) (list 1 (bytes)))
|
|
(check-equal? (decode-varint (bytes 255) ks* kf*) (list 127 (bytes)))
|
|
(check-equal? (decode-varint (bytes 0) ks* kf*) 'short)
|
|
(check-equal? (decode-varint (bytes 1 128) ks* kf*) (list 128 (bytes)))
|
|
(check-equal? (decode-varint (bytes 1 128 99) ks* kf*) (list 128 (bytes 99)))
|
|
(check-equal? (decode-varint (bytes 1 255) ks* kf*) (list 255 (bytes)))
|
|
(check-equal? (decode-varint (bytes 2 128) ks* kf*) (list 256 (bytes)))
|
|
(check-equal? (decode-varint (bytes #b00000010 #b10101100) ks* kf*) (list 300 (bytes)))
|
|
(check-equal? (decode-varint (bytes 3 92 107 20 128) ks* kf*) (list 1000000000 (bytes)))
|
|
(check-equal? (decode-varint (bytes 3 92 107 20 128 99) ks* kf*) (list 1000000000 (bytes 99))))
|