#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))))