#lang restructure/racket (require (prefix-in utils- "utils.rkt") "array.rkt" "number.rkt") (provide (all-defined-out)) #| approximates https://github.com/mbutterick/restructure/blob/master/src/LazyArray.coffee |# (define-subclass object% (InnerLazyArray type [length_ #f] [stream #f] [ctx #f]) (define base (and stream (· stream pos))) (define items (mhash)) ; rather than empty array (define/public-final (get index) (cond [(or (< index 0) (>= index length_)) #f] [else (define item (with-handlers ([exn:fail? (λ _ #f)]) (ref items index))) (or item (let () (define pos_ (· stream pos)) (send stream pos (+ base (* (send type size #f ctx) index))) (define new-item (send type decode stream ctx)) (ref-set! items index new-item) (send stream pos pos_) new-item))])) (define/public-final (toArray) (for/list ([i (in-range length_)]) (get i))) (define/public-final (inspect) (format "~a" (toArray)))) (define-subclass ArrayT (LazyArray) (inherit-field length_ type) (define/override (decode stream [parent #f]) (define pos (· stream pos)) (define length__ (utils-resolveLength length_ stream parent)) (when (NumberT? length_) ;; define hidden properties (set! parent (mhash 'parent parent '_startOffset pos '_currentOffset 0 '_length length_))) (define res (+InnerLazyArray type length__ stream parent)) (send stream pos (+ (· stream pos) (* length__ (send type size #f parent)))) res) (define/override (size [val #f] [ctx #f]) (super size (if (InnerLazyArray? val) (send val toArray) val) ctx)) (define/override (encode stream val [ctx #f]) (super encode stream (if (InnerLazyArray? val) (send val toArray) val) ctx))) #;(test-module (require "stream.rkt") (define bstr #"ABCD1234") (define ds (+DecodeStream bstr)) (define la (+LazyArray uint8 4)) (define ila (send la decode ds)) (check-equal? (send ds pos) 4) (check-equal? (send ila get 1) 66) (check-equal? (send ila get 3) 68) (check-equal? (send ds pos) 4) (check-equal? (send ila toArray) '(65 66 67 68)) (define la2 (+LazyArray int16be (λ (t) 4))) (define es (+EncodeStream)) (send la2 encode es '(1 2 3 4)) (check-equal? (send es dump) #"\0\1\0\2\0\3\0\4") (check-equal? (send (send la2 decode (+DecodeStream #"\0\1\0\2\0\3\0\4")) toArray) '(1 2 3 4)) )