You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
typesetting/pitfall/restructure/number.rkt

96 lines
3.6 KiB
Racket

#lang restructure/racket
7 years ago
(require "decodestream.rkt" "encodestream.rkt" "streamcoder.rkt")
(provide Number)
7 years ago
#|
approximates
https://github.com/mbutterick/restructure/blob/master/src/Number.coffee
|#
(define (ends-with-8? type)
(define str (symbol->string type))
(equal? (substring str (sub1 (string-length str))) "8"))
7 years ago
(define (signed-type? type)
(not (equal? "U" (substring (symbol->string type) 0 1))))
(test-module
7 years ago
(check-false (signed-type? 'UInt16))
(check-true (signed-type? 'Int16)))
7 years ago
(define-subclass RStreamcoder (Number [type 'UInt16] [endian (if (system-big-endian?) 'BE 'LE)])
7 years ago
(getter-field [fn (string->symbol (format "~a~a" type (if (ends-with-8? type) "" endian)))])
7 years ago
7 years ago
(unless (hash-has-key? type-sizes fn)
7 years ago
(raise-argument-error 'Number "valid type and endian" (format "~v ~v" type endian)))
7 years ago
(getter-field [size (hash-ref type-sizes fn)])
7 years ago
(define/augment (decode stream [res #f])
(define bstr (send stream read size))
7 years ago
(if (= 1 size)
(bytes-ref bstr 0)
7 years ago
(integer-bytes->integer bstr (signed-type? type) (eq? endian 'BE))))
7 years ago
(define/augment (encode stream val)
7 years ago
(define bstr
(if (= 1 size)
(bytes val)
7 years ago
(integer->integer-bytes val size (signed-type? type) (eq? endian 'BE))))
7 years ago
(if stream (send stream write bstr) bstr)))
(test-module
7 years ago
(let ([o (make-object Number 'UInt16 'LE)]
7 years ago
[ip (make-object RDecodeStream (bytes 1 2 3 4))])
(check-equal? (send o decode ip) 513) ;; 1000 0000 0100 0000
7 years ago
(check-equal? (send o decode ip) 1027) ;; 1100 0000 0010 0000
7 years ago
(check-equal? (send o encode #f 513) (bytes 1 2))
(check-equal? (send o encode #f 1027) (bytes 3 4)))
7 years ago
(let ([o (make-object Number 'UInt16 'BE)]
7 years ago
[ip (make-object RDecodeStream (bytes 1 2 3 4))])
(check-equal? (send o decode ip) 258) ;; 0100 0000 1000 0000
7 years ago
(check-equal? (send o decode ip) 772) ;; 0010 0000 1100 0000
7 years ago
(check-equal? (send o encode #f 258) (bytes 1 2))
(check-equal? (send o encode #f 772) (bytes 3 4))))
(test-module
7 years ago
(check-equal? (send (make-object Number 'UInt8) size) 1)
(check-equal? (send (make-object Number) size) 2)
(check-equal? (send (make-object Number 'UInt32) size) 4)
(check-equal? (send (make-object Number 'Double) size) 8))
(require (for-syntax "decodestream.rkt" racket/match))
;; use keys of type-sizes hash to generate corresponding number definitions
(define-macro (make-int-types)
(with-pattern ([((ID BASE ENDIAN) ...) (for/list ([k (in-hash-keys type-sizes)])
7 years ago
(define kstr (format "~a" k))
(match-define (list* prefix suffix _)
(regexp-split #rx"(?=[BL]E|$)" kstr))
(map string->symbol
(list (string-downcase kstr)
prefix
(if (positive? (string-length suffix))
suffix
(if (system-big-endian?) "BE" "LE")))))]
7 years ago
[(ID ...) (suffix-id #'(ID ...) #:context caller-stx)])
7 years ago
#'(begin (define+provide ID (make-object Number 'BASE 'ENDIAN)) ...)))
7 years ago
(make-int-types)
(test-module
(check-equal? (send uint8 size) 1)
(check-equal? (send uint16 size) 2)
(check-equal? (send uint32 size) 4)
(check-equal? (send double size) 8))
7 years ago
(require "encodestream.rkt")
(define n (make-object Number 'UInt32))
(send n encode (make-object REncodeStream) 2351070438)