glory
parent
57e70b5802
commit
1b8557373b
@ -1,5 +0,0 @@
|
||||
#lang racket/base
|
||||
(require "private/racket.rkt")
|
||||
|
||||
|
||||
(r+p "private/base.rkt")
|
@ -1,5 +1,44 @@
|
||||
#lang racket/base
|
||||
(require "private/racket.rkt")
|
||||
(provide (all-defined-out))
|
||||
|
||||
#|
|
||||
approximates
|
||||
https://github.com/mbutterick/restructure/blob/master/src/Bitfield.coffee
|
||||
|#
|
||||
|
||||
(r+p "private/bitfield.rkt")
|
||||
(define-subclass Streamcoder (Bitfield type [flags empty])
|
||||
(unless (andmap (λ (f) (or (key? f) (not f))) flags)
|
||||
(raise-argument-error 'Bitfield "list of keys" flags))
|
||||
|
||||
(define/augment (decode stream . _)
|
||||
(define flag-hash (mhasheq))
|
||||
(for* ([val (in-value (send type decode stream))]
|
||||
[(flag i) (in-indexed flags)]
|
||||
#:when flag)
|
||||
(hash-set! flag-hash flag (bitwise-bit-set? val i)))
|
||||
flag-hash)
|
||||
|
||||
(define/augment (size . _) (send type size))
|
||||
|
||||
(define/augment (encode port flag-hash [ctx #f])
|
||||
(define bit-int (for/sum ([(flag i) (in-indexed flags)]
|
||||
#:when (and flag (ref flag-hash flag)))
|
||||
(arithmetic-shift 1 i)))
|
||||
(send type encode port bit-int))
|
||||
|
||||
(define/override (get-class-name) 'Bitfield))
|
||||
|
||||
|
||||
(test-module
|
||||
(require "number.rkt")
|
||||
(define bfer (+Bitfield uint16be '(bold italic underline #f shadow condensed extended)))
|
||||
(define bf (send bfer decode #"\0\25"))
|
||||
(check-equal? (length (ref-keys bf)) 6) ; omits #f flag
|
||||
(check-true (ref bf 'bold))
|
||||
(check-true (ref bf 'underline))
|
||||
(check-true (ref bf 'shadow))
|
||||
(check-false (ref bf 'italic))
|
||||
(check-false (ref bf 'condensed))
|
||||
(check-false (ref bf 'extended))
|
||||
(check-equal? (encode bfer bf #f) #"\0\25"))
|
@ -1,5 +1,56 @@
|
||||
#lang racket/base
|
||||
(require "private/racket.rkt")
|
||||
(require "number.rkt" "utils.rkt")
|
||||
(provide (all-defined-out))
|
||||
|
||||
#|
|
||||
approximates
|
||||
https://github.com/mbutterick/restructure/blob/master/src/Buffer.coffee
|
||||
|#
|
||||
|
||||
(r+p "private/buffer.rkt")
|
||||
#|
|
||||
A Buffer is a container object for any data object that supports random access
|
||||
A Node Buffer object is basically a byte string.
|
||||
First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.
|
||||
A Restructure RBuffer object is separate.
|
||||
|#
|
||||
|
||||
(define (+Buffer xs [type #f])
|
||||
((if (string? xs)
|
||||
string->bytes/utf-8
|
||||
list->bytes) xs))
|
||||
|
||||
(define-subclass xenomorph-base% (RBuffer [len #xffff])
|
||||
|
||||
(define/augment (decode port [parent #f])
|
||||
(define decoded-len (resolve-length len port parent))
|
||||
(read-bytes decoded-len port))
|
||||
|
||||
(define/augment (size [val #f] [parent #f])
|
||||
(when val (unless (bytes? val)
|
||||
(raise-argument-error 'Buffer:size "bytes" val)))
|
||||
(if val
|
||||
(bytes-length val)
|
||||
(resolve-length len val parent)))
|
||||
|
||||
(define/augment (encode port buf [parent #f])
|
||||
(unless (bytes? buf)
|
||||
(raise-argument-error 'Buffer:encode "bytes" buf))
|
||||
(define op (or port (open-output-bytes)))
|
||||
(when (NumberT? len)
|
||||
(send len encode op (length buf)))
|
||||
(write-bytes buf op)
|
||||
(unless port (get-output-bytes op))))
|
||||
|
||||
(define-subclass RBuffer (BufferT))
|
||||
|
||||
|
||||
#;(test-module
|
||||
(require "stream.rkt")
|
||||
(define stream (+DecodeStream #"\2BCDEF"))
|
||||
(define S (+String uint8 'utf8))
|
||||
(check-equal? (send S decode stream) "BC")
|
||||
(define os (+EncodeStream))
|
||||
(send S encode os "Mike")
|
||||
(check-equal? (send os dump) #"\4Mike")
|
||||
(check-equal? (send (+String) size "foobar") 6))
|
@ -1,5 +1,23 @@
|
||||
#lang racket/base
|
||||
(require "private/racket.rkt")
|
||||
(provide (all-defined-out))
|
||||
|
||||
#|
|
||||
approximates
|
||||
https://github.com/mbutterick/restructure/blob/master/src/Enum.coffee
|
||||
|#
|
||||
|
||||
(define-subclass xenomorph-base% (Enum type [options empty])
|
||||
|
||||
(define/augment (decode stream . _)
|
||||
(define index (send type decode stream))
|
||||
(or (list-ref options index) index))
|
||||
|
||||
(define/augment (size . _) (send type size))
|
||||
|
||||
(define/augment (encode stream val [ctx #f])
|
||||
(define index (index-of options val))
|
||||
(unless index
|
||||
(raise-argument-error 'Enum:encode "valid option" val))
|
||||
(send type encode stream index)))
|
||||
|
||||
(r+p "private/enum.rkt")
|
@ -1,5 +1,77 @@
|
||||
#lang racket/base
|
||||
(require "private/racket.rkt")
|
||||
(require "utils.rkt" "array.rkt" "number.rkt")
|
||||
(provide (all-defined-out))
|
||||
|
||||
#|
|
||||
approximates
|
||||
https://github.com/mbutterick/restructure/blob/master/src/LazyArray.coffee
|
||||
|#
|
||||
|
||||
(define (get o i) (send o get i))
|
||||
(define (LazyArray->list o) (send o to-list))
|
||||
|
||||
(define-subclass object% (InnerLazyArray type [len #f] [port-in #f] [ctx #f])
|
||||
(field ([port port] (cond
|
||||
[(bytes? port-in) (open-input-bytes port-in)]
|
||||
[(port? port-in) port-in]
|
||||
[else (raise-argument-error 'LazyArray "port" port)])))
|
||||
(define starting-pos (pos port))
|
||||
(define item-cache (mhasheqv)) ; integer-keyed hash, rather than list
|
||||
|
||||
|
||||
(define/public-final (get index)
|
||||
(unless (<= 0 index (sub1 len))
|
||||
(raise-argument-error 'LazyArray:get (format "index in range 0 to ~a" (sub1 len)) index))
|
||||
(ref! item-cache index (λ ()
|
||||
(define orig-pos (pos port))
|
||||
(pos port (+ starting-pos (* (send type size #f ctx) index)))
|
||||
(define new-item (send type decode port ctx))
|
||||
(pos port orig-pos)
|
||||
new-item)))
|
||||
|
||||
(define/public-final (to-list)
|
||||
(for/list ([i (in-range len)])
|
||||
(get i))))
|
||||
|
||||
|
||||
(define-subclass ArrayT (LazyArray)
|
||||
(inherit-field len type)
|
||||
|
||||
(define/override (decode port [parent #f])
|
||||
(define starting-pos (pos port)) ; ! placement matters. `resolve-length` will change `pos`
|
||||
(define decoded-len (resolve-length len port parent))
|
||||
(let ([parent (if (NumberT? len)
|
||||
(mhasheq 'parent parent
|
||||
'_startOffset starting-pos
|
||||
'_currentOffset 0
|
||||
'_length len)
|
||||
parent)])
|
||||
(define res (+InnerLazyArray type decoded-len port parent))
|
||||
(pos port (+ (pos port) (* decoded-len (send type size #f parent))))
|
||||
res))
|
||||
|
||||
(define/override (size [val #f] [ctx #f])
|
||||
(super size (if (InnerLazyArray? val)
|
||||
(send val to-list)
|
||||
val) ctx))
|
||||
|
||||
(define/override (encode port val [ctx #f])
|
||||
(super encode port (if (InnerLazyArray? val)
|
||||
(send val to-list)
|
||||
val) ctx)))
|
||||
|
||||
(test-module
|
||||
(define bstr #"ABCD1234")
|
||||
(define ds (open-input-bytes bstr))
|
||||
(define la (+LazyArray uint8 4))
|
||||
(define ila (decode la ds))
|
||||
(check-equal? (pos ds) 4)
|
||||
(check-equal? (get ila 1) 66)
|
||||
(check-equal? (get ila 3) 68)
|
||||
(check-equal? (pos ds) 4)
|
||||
(check-equal? (LazyArray->list ila) '(65 66 67 68))
|
||||
(define la2 (+LazyArray int16be (λ (t) 4)))
|
||||
(check-equal? (encode la2 '(1 2 3 4) #f) #"\0\1\0\2\0\3\0\4")
|
||||
(check-equal? (send (decode la2 (open-input-bytes #"\0\1\0\2\0\3\0\4")) to-list) '(1 2 3 4)))
|
||||
|
||||
(r+p "private/lazy-array.rkt")
|
@ -1,5 +1,28 @@
|
||||
#lang racket/base
|
||||
(require "private/racket.rkt")
|
||||
(provide (all-defined-out))
|
||||
|
||||
#|
|
||||
approximates
|
||||
https://github.com/mbutterick/restructure/blob/master/src/Optional.coffee
|
||||
|#
|
||||
|
||||
(define-subclass xenomorph-base% (Optional type [condition #t])
|
||||
|
||||
(define (resolve-condition parent)
|
||||
(if (procedure? condition)
|
||||
(condition parent)
|
||||
condition))
|
||||
|
||||
(define/augment (decode stream parent)
|
||||
(when (resolve-condition parent)
|
||||
(send type decode stream parent)))
|
||||
|
||||
(define/augment (size val parent)
|
||||
(when (resolve-condition parent)
|
||||
(send type size val parent)))
|
||||
|
||||
(define/augment (encode stream val parent)
|
||||
(when (resolve-condition parent)
|
||||
(send type encode stream val parent))))
|
||||
|
||||
(r+p "private/optional.rkt")
|
@ -1,5 +1,102 @@
|
||||
#lang racket/base
|
||||
(require "private/racket.rkt")
|
||||
(require racket/undefined)
|
||||
(provide (all-defined-out))
|
||||
|
||||
#|
|
||||
approximates
|
||||
https://github.com/mbutterick/restructure/blob/master/src/Pointer.coffee
|
||||
|#
|
||||
|
||||
(r+p "private/pointer.rkt")
|
||||
(define (resolve-void-pointer type val)
|
||||
(cond
|
||||
[type (values type val)]
|
||||
[(VoidPointer? val) (values (· val type) (· val value))]
|
||||
[else (raise-argument-error 'Pointer:size "VoidPointer" val)]))
|
||||
|
||||
(define (find-top-ctx ctx)
|
||||
(cond
|
||||
[(· ctx parent) => find-top-ctx]
|
||||
[else ctx]))
|
||||
|
||||
(define-subclass xenomorph-base% (Pointer offset-type type-in [options (mhasheq)])
|
||||
(field [type (and (not (eq? type-in 'void)) type-in)])
|
||||
(define pointer-style (or (· options type) 'local))
|
||||
(define allow-null (or (· options allowNull) #t))
|
||||
(define null-value (or (· options nullValue) 0))
|
||||
(define lazy (· options lazy))
|
||||
(define relative-getter-or-0 (or (· options relativeTo) (λ (ctx) 0))) ; changed this to a simple lambda
|
||||
|
||||
(define/augment (decode port [ctx #f])
|
||||
(define offset (send offset-type decode port ctx))
|
||||
(cond
|
||||
[(and allow-null (= offset null-value)) #f] ; handle null pointers
|
||||
[else
|
||||
(define relative (+ (caseq pointer-style
|
||||
[(local) (· ctx _startOffset)]
|
||||
[(immediate) (- (pos port) (send offset-type size))]
|
||||
[(parent) (· ctx parent _startOffset)]
|
||||
[(global) (or (· (find-top-ctx ctx) _startOffset) 0)]
|
||||
[else (error 'unknown-pointer-style)])
|
||||
(relative-getter-or-0 ctx)))
|
||||
(define ptr (+ offset relative))
|
||||
(cond
|
||||
[type (define val (void))
|
||||
(define (decode-value)
|
||||
(cond
|
||||
[(not (void? val)) val]
|
||||
[else
|
||||
(define orig-pos (pos port))
|
||||
(pos port ptr)
|
||||
(set! val (send type decode port ctx))
|
||||
(pos port orig-pos)
|
||||
val]))
|
||||
(if lazy
|
||||
(LazyThunk decode-value)
|
||||
(decode-value))]
|
||||
[else ptr])]))
|
||||
|
||||
|
||||
(define/augment (size [val #f] [ctx #f])
|
||||
(let*-values ([(parent) ctx]
|
||||
[(ctx) (caseq pointer-style
|
||||
[(local immediate) ctx]
|
||||
[(parent) (· ctx parent)]
|
||||
[(global) (find-top-ctx ctx)]
|
||||
[else (error 'unknown-pointer-style)])]
|
||||
[(type val) (resolve-void-pointer type val)])
|
||||
(when (and val ctx)
|
||||
(ref-set! ctx 'pointerSize (and (· ctx pointerSize)
|
||||
(+ (· ctx pointerSize) (send type size val parent)))))
|
||||
(send offset-type size)))
|
||||
|
||||
|
||||
(define/augment (encode port val [ctx #f])
|
||||
(unless ctx
|
||||
;; todo: furnish default pointer context? adapt from Struct?
|
||||
(raise-argument-error 'Pointer:encode "valid pointer context" ctx))
|
||||
(if (not val)
|
||||
(send offset-type encode port null-value)
|
||||
(let* ([parent ctx]
|
||||
[ctx (caseq pointer-style
|
||||
[(local immediate) ctx]
|
||||
[(parent) (· ctx parent)]
|
||||
[(global) (find-top-ctx ctx)]
|
||||
[else (error 'unknown-pointer-style)])]
|
||||
[relative (+ (caseq pointer-style
|
||||
[(local parent) (· ctx startOffset)]
|
||||
[(immediate) (+ (pos port) (send offset-type size val parent))]
|
||||
[(global) 0])
|
||||
(relative-getter-or-0 (· parent val)))])
|
||||
|
||||
(send offset-type encode port (- (· ctx pointerOffset) relative))
|
||||
|
||||
(let-values ([(type val) (resolve-void-pointer type val)])
|
||||
(ref-set! ctx 'pointers (append (· ctx pointers) (list (mhasheq 'type type
|
||||
'val val
|
||||
'parent parent))))
|
||||
(ref-set! ctx 'pointerOffset (+ (· ctx pointerOffset) (send type size val parent))))))))
|
||||
|
||||
|
||||
;; A pointer whose type is determined at decode time
|
||||
(define-subclass object% (VoidPointer type value))
|
||||
|
@ -1,44 +0,0 @@
|
||||
#lang racket/base
|
||||
(require "racket.rkt")
|
||||
(provide (all-defined-out))
|
||||
|
||||
#|
|
||||
approximates
|
||||
https://github.com/mbutterick/restructure/blob/master/src/Bitfield.coffee
|
||||
|#
|
||||
|
||||
(define-subclass Streamcoder (Bitfield type [flags empty])
|
||||
(unless (andmap (λ (f) (or (key? f) (not f))) flags)
|
||||
(raise-argument-error 'Bitfield "list of keys" flags))
|
||||
|
||||
(define/augment (decode stream . _)
|
||||
(define flag-hash (mhasheq))
|
||||
(for* ([val (in-value (send type decode stream))]
|
||||
[(flag i) (in-indexed flags)]
|
||||
#:when flag)
|
||||
(hash-set! flag-hash flag (bitwise-bit-set? val i)))
|
||||
flag-hash)
|
||||
|
||||
(define/augment (size . _) (send type size))
|
||||
|
||||
(define/augment (encode port flag-hash [ctx #f])
|
||||
(define bit-int (for/sum ([(flag i) (in-indexed flags)]
|
||||
#:when (and flag (ref flag-hash flag)))
|
||||
(arithmetic-shift 1 i)))
|
||||
(send type encode port bit-int))
|
||||
|
||||
(define/override (get-class-name) 'Bitfield))
|
||||
|
||||
|
||||
(test-module
|
||||
(require "number.rkt")
|
||||
(define bfer (+Bitfield uint16be '(bold italic underline #f shadow condensed extended)))
|
||||
(define bf (send bfer decode #"\0\25"))
|
||||
(check-equal? (length (ref-keys bf)) 6) ; omits #f flag
|
||||
(check-true (ref bf 'bold))
|
||||
(check-true (ref bf 'underline))
|
||||
(check-true (ref bf 'shadow))
|
||||
(check-false (ref bf 'italic))
|
||||
(check-false (ref bf 'condensed))
|
||||
(check-false (ref bf 'extended))
|
||||
(check-equal? (encode bfer bf #f) #"\0\25"))
|
@ -1,56 +0,0 @@
|
||||
#lang racket/base
|
||||
(require "racket.rkt")
|
||||
(require "number.rkt" "utils.rkt")
|
||||
(provide (all-defined-out))
|
||||
|
||||
#|
|
||||
approximates
|
||||
https://github.com/mbutterick/restructure/blob/master/src/Buffer.coffee
|
||||
|#
|
||||
|
||||
#|
|
||||
A Buffer is a container object for any data object that supports random access
|
||||
A Node Buffer object is basically a byte string.
|
||||
First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.
|
||||
A Restructure RBuffer object is separate.
|
||||
|#
|
||||
|
||||
(define (+Buffer xs [type #f])
|
||||
((if (string? xs)
|
||||
string->bytes/utf-8
|
||||
list->bytes) xs))
|
||||
|
||||
(define-subclass xenomorph-base% (RBuffer [len #xffff])
|
||||
|
||||
(define/augment (decode port [parent #f])
|
||||
(define decoded-len (resolve-length len port parent))
|
||||
(read-bytes decoded-len port))
|
||||
|
||||
(define/augment (size [val #f] [parent #f])
|
||||
(when val (unless (bytes? val)
|
||||
(raise-argument-error 'Buffer:size "bytes" val)))
|
||||
(if val
|
||||
(bytes-length val)
|
||||
(resolve-length len val parent)))
|
||||
|
||||
(define/augment (encode port buf [parent #f])
|
||||
(unless (bytes? buf)
|
||||
(raise-argument-error 'Buffer:encode "bytes" buf))
|
||||
(define op (or port (open-output-bytes)))
|
||||
(when (NumberT? len)
|
||||
(send len encode op (length buf)))
|
||||
(write-bytes buf op)
|
||||
(unless port (get-output-bytes op))))
|
||||
|
||||
(define-subclass RBuffer (BufferT))
|
||||
|
||||
|
||||
#;(test-module
|
||||
(require "stream.rkt")
|
||||
(define stream (+DecodeStream #"\2BCDEF"))
|
||||
(define S (+String uint8 'utf8))
|
||||
(check-equal? (send S decode stream) "BC")
|
||||
(define os (+EncodeStream))
|
||||
(send S encode os "Mike")
|
||||
(check-equal? (send os dump) #"\4Mike")
|
||||
(check-equal? (send (+String) size "foobar") 6))
|
@ -1,23 +0,0 @@
|
||||
#lang racket/base
|
||||
(require "racket.rkt")
|
||||
(provide (all-defined-out))
|
||||
|
||||
#|
|
||||
approximates
|
||||
https://github.com/mbutterick/restructure/blob/master/src/Enum.coffee
|
||||
|#
|
||||
|
||||
(define-subclass xenomorph-base% (Enum type [options empty])
|
||||
|
||||
(define/augment (decode stream . _)
|
||||
(define index (send type decode stream))
|
||||
(or (list-ref options index) index))
|
||||
|
||||
(define/augment (size . _) (send type size))
|
||||
|
||||
(define/augment (encode stream val [ctx #f])
|
||||
(define index (index-of options val))
|
||||
(unless index
|
||||
(raise-argument-error 'Enum:encode "valid option" val))
|
||||
(send type encode stream index)))
|
||||
|
@ -1,77 +0,0 @@
|
||||
#lang racket/base
|
||||
(require "racket.rkt")
|
||||
(require "utils.rkt" "array.rkt" "number.rkt")
|
||||
(provide (all-defined-out))
|
||||
|
||||
#|
|
||||
approximates
|
||||
https://github.com/mbutterick/restructure/blob/master/src/LazyArray.coffee
|
||||
|#
|
||||
|
||||
(define (get o i) (send o get i))
|
||||
(define (LazyArray->list o) (send o to-list))
|
||||
|
||||
(define-subclass object% (InnerLazyArray type [len #f] [port-in #f] [ctx #f])
|
||||
(field ([port port] (cond
|
||||
[(bytes? port-in) (open-input-bytes port-in)]
|
||||
[(port? port-in) port-in]
|
||||
[else (raise-argument-error 'LazyArray "port" port)])))
|
||||
(define starting-pos (pos port))
|
||||
(define item-cache (mhasheqv)) ; integer-keyed hash, rather than list
|
||||
|
||||
|
||||
(define/public-final (get index)
|
||||
(unless (<= 0 index (sub1 len))
|
||||
(raise-argument-error 'LazyArray:get (format "index in range 0 to ~a" (sub1 len)) index))
|
||||
(ref! item-cache index (λ ()
|
||||
(define orig-pos (pos port))
|
||||
(pos port (+ starting-pos (* (send type size #f ctx) index)))
|
||||
(define new-item (send type decode port ctx))
|
||||
(pos port orig-pos)
|
||||
new-item)))
|
||||
|
||||
(define/public-final (to-list)
|
||||
(for/list ([i (in-range len)])
|
||||
(get i))))
|
||||
|
||||
|
||||
(define-subclass ArrayT (LazyArray)
|
||||
(inherit-field len type)
|
||||
|
||||
(define/override (decode port [parent #f])
|
||||
(define starting-pos (pos port)) ; ! placement matters. `resolve-length` will change `pos`
|
||||
(define decoded-len (resolve-length len port parent))
|
||||
(let ([parent (if (NumberT? len)
|
||||
(mhasheq 'parent parent
|
||||
'_startOffset starting-pos
|
||||
'_currentOffset 0
|
||||
'_length len)
|
||||
parent)])
|
||||
(define res (+InnerLazyArray type decoded-len port parent))
|
||||
(pos port (+ (pos port) (* decoded-len (send type size #f parent))))
|
||||
res))
|
||||
|
||||
(define/override (size [val #f] [ctx #f])
|
||||
(super size (if (InnerLazyArray? val)
|
||||
(send val to-list)
|
||||
val) ctx))
|
||||
|
||||
(define/override (encode port val [ctx #f])
|
||||
(super encode port (if (InnerLazyArray? val)
|
||||
(send val to-list)
|
||||
val) ctx)))
|
||||
|
||||
(test-module
|
||||
(define bstr #"ABCD1234")
|
||||
(define ds (open-input-bytes bstr))
|
||||
(define la (+LazyArray uint8 4))
|
||||
(define ila (decode la ds))
|
||||
(check-equal? (pos ds) 4)
|
||||
(check-equal? (get ila 1) 66)
|
||||
(check-equal? (get ila 3) 68)
|
||||
(check-equal? (pos ds) 4)
|
||||
(check-equal? (LazyArray->list ila) '(65 66 67 68))
|
||||
(define la2 (+LazyArray int16be (λ (t) 4)))
|
||||
(check-equal? (encode la2 '(1 2 3 4) #f) #"\0\1\0\2\0\3\0\4")
|
||||
(check-equal? (send (decode la2 (open-input-bytes #"\0\1\0\2\0\3\0\4")) to-list) '(1 2 3 4)))
|
||||
|
@ -1,28 +0,0 @@
|
||||
#lang racket/base
|
||||
(require "racket.rkt")
|
||||
(provide (all-defined-out))
|
||||
|
||||
#|
|
||||
approximates
|
||||
https://github.com/mbutterick/restructure/blob/master/src/Optional.coffee
|
||||
|#
|
||||
|
||||
(define-subclass xenomorph-base% (Optional type [condition #t])
|
||||
|
||||
(define (resolve-condition parent)
|
||||
(if (procedure? condition)
|
||||
(condition parent)
|
||||
condition))
|
||||
|
||||
(define/augment (decode stream parent)
|
||||
(when (resolve-condition parent)
|
||||
(send type decode stream parent)))
|
||||
|
||||
(define/augment (size val parent)
|
||||
(when (resolve-condition parent)
|
||||
(send type size val parent)))
|
||||
|
||||
(define/augment (encode stream val parent)
|
||||
(when (resolve-condition parent)
|
||||
(send type encode stream val parent))))
|
||||
|
@ -1,102 +0,0 @@
|
||||
#lang racket/base
|
||||
(require "racket.rkt")
|
||||
(require racket/undefined)
|
||||
(provide (all-defined-out))
|
||||
|
||||
#|
|
||||
approximates
|
||||
https://github.com/mbutterick/restructure/blob/master/src/Pointer.coffee
|
||||
|#
|
||||
|
||||
(define (resolve-void-pointer type val)
|
||||
(cond
|
||||
[type (values type val)]
|
||||
[(VoidPointer? val) (values (· val type) (· val value))]
|
||||
[else (raise-argument-error 'Pointer:size "VoidPointer" val)]))
|
||||
|
||||
(define (find-top-ctx ctx)
|
||||
(cond
|
||||
[(· ctx parent) => find-top-ctx]
|
||||
[else ctx]))
|
||||
|
||||
(define-subclass xenomorph-base% (Pointer offset-type type-in [options (mhasheq)])
|
||||
(field [type (and (not (eq? type-in 'void)) type-in)])
|
||||
(define pointer-style (or (· options type) 'local))
|
||||
(define allow-null (or (· options allowNull) #t))
|
||||
(define null-value (or (· options nullValue) 0))
|
||||
(define lazy (· options lazy))
|
||||
(define relative-getter-or-0 (or (· options relativeTo) (λ (ctx) 0))) ; changed this to a simple lambda
|
||||
|
||||
(define/augment (decode port [ctx #f])
|
||||
(define offset (send offset-type decode port ctx))
|
||||
(cond
|
||||
[(and allow-null (= offset null-value)) #f] ; handle null pointers
|
||||
[else
|
||||
(define relative (+ (caseq pointer-style
|
||||
[(local) (· ctx _startOffset)]
|
||||
[(immediate) (- (pos port) (send offset-type size))]
|
||||
[(parent) (· ctx parent _startOffset)]
|
||||
[(global) (or (· (find-top-ctx ctx) _startOffset) 0)]
|
||||
[else (error 'unknown-pointer-style)])
|
||||
(relative-getter-or-0 ctx)))
|
||||
(define ptr (+ offset relative))
|
||||
(cond
|
||||
[type (define val (void))
|
||||
(define (decode-value)
|
||||
(cond
|
||||
[(not (void? val)) val]
|
||||
[else
|
||||
(define orig-pos (pos port))
|
||||
(pos port ptr)
|
||||
(set! val (send type decode port ctx))
|
||||
(pos port orig-pos)
|
||||
val]))
|
||||
(if lazy
|
||||
(LazyThunk decode-value)
|
||||
(decode-value))]
|
||||
[else ptr])]))
|
||||
|
||||
|
||||
(define/augment (size [val #f] [ctx #f])
|
||||
(let*-values ([(parent) ctx]
|
||||
[(ctx) (caseq pointer-style
|
||||
[(local immediate) ctx]
|
||||
[(parent) (· ctx parent)]
|
||||
[(global) (find-top-ctx ctx)]
|
||||
[else (error 'unknown-pointer-style)])]
|
||||
[(type val) (resolve-void-pointer type val)])
|
||||
(when (and val ctx)
|
||||
(ref-set! ctx 'pointerSize (and (· ctx pointerSize)
|
||||
(+ (· ctx pointerSize) (send type size val parent)))))
|
||||
(send offset-type size)))
|
||||
|
||||
|
||||
(define/augment (encode port val [ctx #f])
|
||||
(unless ctx
|
||||
;; todo: furnish default pointer context? adapt from Struct?
|
||||
(raise-argument-error 'Pointer:encode "valid pointer context" ctx))
|
||||
(if (not val)
|
||||
(send offset-type encode port null-value)
|
||||
(let* ([parent ctx]
|
||||
[ctx (caseq pointer-style
|
||||
[(local immediate) ctx]
|
||||
[(parent) (· ctx parent)]
|
||||
[(global) (find-top-ctx ctx)]
|
||||
[else (error 'unknown-pointer-style)])]
|
||||
[relative (+ (caseq pointer-style
|
||||
[(local parent) (· ctx startOffset)]
|
||||
[(immediate) (+ (pos port) (send offset-type size val parent))]
|
||||
[(global) 0])
|
||||
(relative-getter-or-0 (· parent val)))])
|
||||
|
||||
(send offset-type encode port (- (· ctx pointerOffset) relative))
|
||||
|
||||
(let-values ([(type val) (resolve-void-pointer type val)])
|
||||
(ref-set! ctx 'pointers (append (· ctx pointers) (list (mhasheq 'type type
|
||||
'val val
|
||||
'parent parent))))
|
||||
(ref-set! ctx 'pointerOffset (+ (· ctx pointerOffset) (send type size val parent))))))))
|
||||
|
||||
|
||||
;; A pointer whose type is determined at decode time
|
||||
(define-subclass object% (VoidPointer type value))
|
@ -1,22 +0,0 @@
|
||||
#lang racket/base
|
||||
(require "racket.rkt")
|
||||
(require "utils.rkt")
|
||||
(provide (all-defined-out))
|
||||
|
||||
#|
|
||||
approximates
|
||||
https://github.com/mbutterick/restructure/blob/master/src/Reserved.coffee
|
||||
|#
|
||||
|
||||
(define-subclass xenomorph-base% (Reserved type [count 1])
|
||||
|
||||
(define/augment (decode port parent)
|
||||
(pos port (+ (pos port) (size #f parent)))
|
||||
(void))
|
||||
|
||||
(define/augment (size [val #f] [parent #f])
|
||||
(* (send type size) (resolve-length count #f parent)))
|
||||
|
||||
(define/augment (encode port val [parent #f])
|
||||
(make-bytes (size val parent) 0)))
|
||||
|
@ -1,147 +0,0 @@
|
||||
#lang racket/base
|
||||
(require "racket.rkt")
|
||||
(require racket/dict "struct.rkt")
|
||||
(provide (all-defined-out))
|
||||
|
||||
#|
|
||||
approximates
|
||||
https://github.com/mbuttrackerick/restructure/blob/master/src/VersionedStruct.coffee
|
||||
|#
|
||||
|
||||
|
||||
(define-subclass Struct (VersionedStruct type [versions (dictify)])
|
||||
|
||||
(unless ((disjoin integer? procedure? xenomorph-base%? symbol?) type)
|
||||
(raise-argument-error 'VersionedStruct "integer, function, symbol, or Restructure object" type))
|
||||
(unless (and (dict? versions) (andmap (λ (val) (or (dict? val) (Struct? val))) (map cdr versions)))
|
||||
(raise-argument-error 'VersionedStruct "dict of dicts or Structs" versions))
|
||||
|
||||
(inherit _setup _parse-fields post-decode)
|
||||
(inherit-field fields)
|
||||
(field [forced-version #f]
|
||||
[versionGetter void]
|
||||
[versionSetter void])
|
||||
|
||||
(when (or (key? type) (procedure? type))
|
||||
(set-field! versionGetter this (if (procedure? type)
|
||||
type
|
||||
(λ (parent) (ref parent type))))
|
||||
(set-field! versionSetter this (if (procedure? type)
|
||||
type
|
||||
(λ (parent version) (ref-set! parent type version)))))
|
||||
|
||||
(define/override (decode stream [parent #f] [length 0])
|
||||
(define res (_setup stream parent length))
|
||||
|
||||
(ref-set! res 'version
|
||||
(cond
|
||||
[forced-version] ; for testing purposes: pass an explicit version
|
||||
[(or (key? type) (procedure? type))
|
||||
(unless parent
|
||||
(raise-argument-error 'VersionedStruct:decode "valid parent" parent))
|
||||
(versionGetter parent)]
|
||||
[else (send type decode stream)]))
|
||||
|
||||
(when (ref versions 'header)
|
||||
(_parse-fields stream res (ref versions 'header)))
|
||||
|
||||
(define fields (or (ref versions (ref res 'version)) (raise-argument-error 'VersionedStruct:decode "valid version key" (cons version (· this versions)))))
|
||||
|
||||
|
||||
(cond
|
||||
[(VersionedStruct? fields) (send fields decode stream parent)]
|
||||
[else
|
||||
(_parse-fields stream res fields)
|
||||
res]))
|
||||
|
||||
(define/public-final (force-version! version)
|
||||
(set! forced-version version))
|
||||
|
||||
(define/override (encode stream val [parent #f])
|
||||
(unless (hash? val)
|
||||
(raise-argument-error 'VersionedStruct:encode "hash" val))
|
||||
|
||||
(define ctx (mhash 'pointers empty
|
||||
'startOffset (pos stream)
|
||||
'parent parent
|
||||
'val val
|
||||
'pointerSize 0))
|
||||
|
||||
(ref-set! ctx 'pointerOffset (+ (pos stream) (size val ctx #f)))
|
||||
|
||||
(when (not (or (key? type) (procedure? type)))
|
||||
(send type encode stream (or forced-version (· val version))))
|
||||
|
||||
(when (ref versions 'header)
|
||||
(for ([(key type) (in-dict (ref versions 'header))])
|
||||
(send type encode stream (ref val key) ctx)))
|
||||
|
||||
(define fields (or (ref versions (or forced-version (· val version))) (raise-argument-error 'VersionedStruct:encode "valid version key" version)))
|
||||
|
||||
(unless (andmap (λ (key) (member key (ref-keys val))) (ref-keys fields))
|
||||
(raise-argument-error 'VersionedStruct:encode (format "hash that contains superset of Struct keys: ~a" (dict-keys fields)) (hash-keys val)))
|
||||
|
||||
(for ([(key type) (in-dict fields)])
|
||||
(send type encode stream (ref val key) ctx))
|
||||
|
||||
(for ([ptr (in-list (ref ctx 'pointers))])
|
||||
(send (ref ptr 'type) encode stream (ref ptr 'val) (ref ptr 'parent))))
|
||||
|
||||
|
||||
(define/override (size [val #f] [parent #f] [includePointers #t])
|
||||
(unless (or val forced-version)
|
||||
(raise-argument-error 'VersionedStruct:size "value" val))
|
||||
|
||||
(define ctx (mhash 'parent parent
|
||||
'val val
|
||||
'pointerSize 0))
|
||||
|
||||
(+ (if (not (or (key? type) (procedure? type)))
|
||||
(send type size (or forced-version (ref val 'version)) ctx)
|
||||
0)
|
||||
|
||||
(for/sum ([(key type) (in-dict (or (ref versions 'header) empty))])
|
||||
(send type size (and val (ref val key)) ctx))
|
||||
|
||||
(let ([fields (or (ref versions (or forced-version (ref val 'version)))
|
||||
(raise-argument-error 'VersionedStruct:encode "valid version key" version))])
|
||||
(for/sum ([(key type) (in-dict fields)])
|
||||
(send type size (and val (ref val key)) ctx)))
|
||||
|
||||
(if includePointers (ref ctx 'pointerSize) 0))))
|
||||
|
||||
#;(test-module
|
||||
(require "number.rkt")
|
||||
(define (random-pick xs) (list-ref xs (random (length xs))))
|
||||
(check-exn exn:fail:contract? (λ () (+VersionedStruct 42 42)))
|
||||
|
||||
;; make random versioned structs and make sure we can round trip
|
||||
#;(for ([i (in-range 1)])
|
||||
(define field-types (for/list ([i (in-range 1)])
|
||||
(random-pick (list uint8 uint16be uint16le uint32be uint32le double))))
|
||||
(define num-versions 20)
|
||||
(define which-struct (random num-versions))
|
||||
(define struct-versions (for/list ([v (in-range num-versions)])
|
||||
(cons v (for/list ([num-type (in-list field-types)])
|
||||
(cons (gensym) num-type)))))
|
||||
(define vs (+VersionedStruct which-struct struct-versions))
|
||||
(define struct-size (for/sum ([num-type (in-list (map cdr (ref struct-versions which-struct)))])
|
||||
(send num-type size)))
|
||||
(define bs (apply bytes (for/list ([i (in-range struct-size)])
|
||||
(random 256))))
|
||||
(check-equal? (send vs encode #f (send vs decode bs)) bs))
|
||||
|
||||
(define s (+Struct (dictify 'a uint8 'b uint8 'c uint8)))
|
||||
(check-equal? (send s size) 3)
|
||||
(define vs (+VersionedStruct uint8 (dictify 1 (dictify 'd s) 2 (dictify 'e s 'f s))))
|
||||
(send vs force-version! 1)
|
||||
(check-equal? (send vs size) 6)
|
||||
#|
|
||||
(define s2 (+Struct (dictify 'a vs)))
|
||||
(check-equal? (send s2 size) 6)
|
||||
(define vs2 (+VersionedStruct (λ (p) 2) (dictify 1 vs 2 vs)))
|
||||
(check-equal? (send vs2 size) 6)
|
||||
|#
|
||||
)
|
||||
|
||||
|
@ -1,5 +1,22 @@
|
||||
#lang racket/base
|
||||
(require "private/racket.rkt")
|
||||
(require "utils.rkt")
|
||||
(provide (all-defined-out))
|
||||
|
||||
#|
|
||||
approximates
|
||||
https://github.com/mbutterick/restructure/blob/master/src/Reserved.coffee
|
||||
|#
|
||||
|
||||
(define-subclass xenomorph-base% (Reserved type [count 1])
|
||||
|
||||
(define/augment (decode port parent)
|
||||
(pos port (+ (pos port) (size #f parent)))
|
||||
(void))
|
||||
|
||||
(define/augment (size [val #f] [parent #f])
|
||||
(* (send type size) (resolve-length count #f parent)))
|
||||
|
||||
(define/augment (encode port val [parent #f])
|
||||
(make-bytes (size val parent) 0)))
|
||||
|
||||
(r+p "private/reserved.rkt")
|
@ -1,5 +1,5 @@
|
||||
#lang racket/base
|
||||
(require "racket.rkt")
|
||||
(require "private/racket.rkt")
|
||||
(provide type-sizes get-type-size)
|
||||
|
||||
(define-values (int-keys byte-values) (for*/lists (int-keys byte-values)
|
@ -1,5 +1,5 @@
|
||||
#lang racket/base
|
||||
(require "racket.rkt")
|
||||
(require "private/racket.rkt")
|
||||
(require racket/generic racket/private/generic-methods)
|
||||
(provide (all-defined-out))
|
||||
|
@ -1,5 +1,5 @@
|
||||
#lang racket/base
|
||||
(require "racket.rkt")
|
||||
(require "private/racket.rkt")
|
||||
(provide (all-defined-out))
|
||||
(require "number.rkt")
|
||||
|
@ -1,5 +1,147 @@
|
||||
#lang racket/base
|
||||
(require "private/racket.rkt")
|
||||
(require racket/dict "struct.rkt")
|
||||
(provide (all-defined-out))
|
||||
|
||||
#|
|
||||
approximates
|
||||
https://github.com/mbuttrackerick/restructure/blob/master/src/VersionedStruct.coffee
|
||||
|#
|
||||
|
||||
|
||||
(define-subclass Struct (VersionedStruct type [versions (dictify)])
|
||||
|
||||
(unless ((disjoin integer? procedure? xenomorph-base%? symbol?) type)
|
||||
(raise-argument-error 'VersionedStruct "integer, function, symbol, or Restructure object" type))
|
||||
(unless (and (dict? versions) (andmap (λ (val) (or (dict? val) (Struct? val))) (map cdr versions)))
|
||||
(raise-argument-error 'VersionedStruct "dict of dicts or Structs" versions))
|
||||
|
||||
(inherit _setup _parse-fields post-decode)
|
||||
(inherit-field fields)
|
||||
(field [forced-version #f]
|
||||
[versionGetter void]
|
||||
[versionSetter void])
|
||||
|
||||
(when (or (key? type) (procedure? type))
|
||||
(set-field! versionGetter this (if (procedure? type)
|
||||
type
|
||||
(λ (parent) (ref parent type))))
|
||||
(set-field! versionSetter this (if (procedure? type)
|
||||
type
|
||||
(λ (parent version) (ref-set! parent type version)))))
|
||||
|
||||
(define/override (decode stream [parent #f] [length 0])
|
||||
(define res (_setup stream parent length))
|
||||
|
||||
(ref-set! res 'version
|
||||
(cond
|
||||
[forced-version] ; for testing purposes: pass an explicit version
|
||||
[(or (key? type) (procedure? type))
|
||||
(unless parent
|
||||
(raise-argument-error 'VersionedStruct:decode "valid parent" parent))
|
||||
(versionGetter parent)]
|
||||
[else (send type decode stream)]))
|
||||
|
||||
(when (ref versions 'header)
|
||||
(_parse-fields stream res (ref versions 'header)))
|
||||
|
||||
(define fields (or (ref versions (ref res 'version)) (raise-argument-error 'VersionedStruct:decode "valid version key" (cons version (· this versions)))))
|
||||
|
||||
|
||||
(cond
|
||||
[(VersionedStruct? fields) (send fields decode stream parent)]
|
||||
[else
|
||||
(_parse-fields stream res fields)
|
||||
res]))
|
||||
|
||||
(define/public-final (force-version! version)
|
||||
(set! forced-version version))
|
||||
|
||||
(define/override (encode stream val [parent #f])
|
||||
(unless (hash? val)
|
||||
(raise-argument-error 'VersionedStruct:encode "hash" val))
|
||||
|
||||
(define ctx (mhash 'pointers empty
|
||||
'startOffset (pos stream)
|
||||
'parent parent
|
||||
'val val
|
||||
'pointerSize 0))
|
||||
|
||||
(ref-set! ctx 'pointerOffset (+ (pos stream) (size val ctx #f)))
|
||||
|
||||
(when (not (or (key? type) (procedure? type)))
|
||||
(send type encode stream (or forced-version (· val version))))
|
||||
|
||||
(when (ref versions 'header)
|
||||
(for ([(key type) (in-dict (ref versions 'header))])
|
||||
(send type encode stream (ref val key) ctx)))
|
||||
|
||||
(define fields (or (ref versions (or forced-version (· val version))) (raise-argument-error 'VersionedStruct:encode "valid version key" version)))
|
||||
|
||||
(unless (andmap (λ (key) (member key (ref-keys val))) (ref-keys fields))
|
||||
(raise-argument-error 'VersionedStruct:encode (format "hash that contains superset of Struct keys: ~a" (dict-keys fields)) (hash-keys val)))
|
||||
|
||||
(for ([(key type) (in-dict fields)])
|
||||
(send type encode stream (ref val key) ctx))
|
||||
|
||||
(for ([ptr (in-list (ref ctx 'pointers))])
|
||||
(send (ref ptr 'type) encode stream (ref ptr 'val) (ref ptr 'parent))))
|
||||
|
||||
|
||||
(define/override (size [val #f] [parent #f] [includePointers #t])
|
||||
(unless (or val forced-version)
|
||||
(raise-argument-error 'VersionedStruct:size "value" val))
|
||||
|
||||
(define ctx (mhash 'parent parent
|
||||
'val val
|
||||
'pointerSize 0))
|
||||
|
||||
(+ (if (not (or (key? type) (procedure? type)))
|
||||
(send type size (or forced-version (ref val 'version)) ctx)
|
||||
0)
|
||||
|
||||
(for/sum ([(key type) (in-dict (or (ref versions 'header) empty))])
|
||||
(send type size (and val (ref val key)) ctx))
|
||||
|
||||
(let ([fields (or (ref versions (or forced-version (ref val 'version)))
|
||||
(raise-argument-error 'VersionedStruct:encode "valid version key" version))])
|
||||
(for/sum ([(key type) (in-dict fields)])
|
||||
(send type size (and val (ref val key)) ctx)))
|
||||
|
||||
(if includePointers (ref ctx 'pointerSize) 0))))
|
||||
|
||||
#;(test-module
|
||||
(require "number.rkt")
|
||||
(define (random-pick xs) (list-ref xs (random (length xs))))
|
||||
(check-exn exn:fail:contract? (λ () (+VersionedStruct 42 42)))
|
||||
|
||||
;; make random versioned structs and make sure we can round trip
|
||||
#;(for ([i (in-range 1)])
|
||||
(define field-types (for/list ([i (in-range 1)])
|
||||
(random-pick (list uint8 uint16be uint16le uint32be uint32le double))))
|
||||
(define num-versions 20)
|
||||
(define which-struct (random num-versions))
|
||||
(define struct-versions (for/list ([v (in-range num-versions)])
|
||||
(cons v (for/list ([num-type (in-list field-types)])
|
||||
(cons (gensym) num-type)))))
|
||||
(define vs (+VersionedStruct which-struct struct-versions))
|
||||
(define struct-size (for/sum ([num-type (in-list (map cdr (ref struct-versions which-struct)))])
|
||||
(send num-type size)))
|
||||
(define bs (apply bytes (for/list ([i (in-range struct-size)])
|
||||
(random 256))))
|
||||
(check-equal? (send vs encode #f (send vs decode bs)) bs))
|
||||
|
||||
(define s (+Struct (dictify 'a uint8 'b uint8 'c uint8)))
|
||||
(check-equal? (send s size) 3)
|
||||
(define vs (+VersionedStruct uint8 (dictify 1 (dictify 'd s) 2 (dictify 'e s 'f s))))
|
||||
(send vs force-version! 1)
|
||||
(check-equal? (send vs size) 6)
|
||||
#|
|
||||
(define s2 (+Struct (dictify 'a vs)))
|
||||
(check-equal? (send s2 size) 6)
|
||||
(define vs2 (+VersionedStruct (λ (p) 2) (dictify 1 vs 2 vs)))
|
||||
(check-equal? (send vs2 size) 6)
|
||||
|#
|
||||
)
|
||||
|
||||
|
||||
(r+p "private/versioned-struct.rkt")
|
Loading…
Reference in New Issue