-
Notifications
You must be signed in to change notification settings - Fork 0
/
util.rkt
163 lines (141 loc) · 5.38 KB
/
util.rkt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#lang racket
(provide
build-ndf-filename
checked-guard
entity-structs
define-serializable
foldl-reordered
bytes-empty?
split-by
take-up-to
chunk-by-size)
(require
(for-syntax threading racket/syntax racket/list)
struct-update
threading
br/cond)
(define (build-ndf-filename #:data? [data? 'entity] name)
(let [(path (case (list 'quote data?)
[('entity) "ndf/entities/"]
[('schema) "ndf/schemas/"]
[('data) "ndf/data/"]
[else (error (format "Unknown data type for filename creation: ~a" data?))]))]
(string-append path (string-append name ".ndf"))))
(define (chunk-by-size chunk-size elements)
(let recur [(n chunk-size)
(chunk '())
(elements elements)]
(cond
((empty? elements) (if (empty? chunk)
'()
(list (reverse chunk))))
((zero? n) (cons (reverse chunk) (chunk-by-size chunk-size elements)))
(else (recur (sub1 n) (cons (car elements) chunk) (cdr elements))))))
(define (foldl-reordered lst initial f)
(foldl f initial lst))
(define entity-structs (make-hash (list)))
(define-syntax (define-serializable stx)
(syntax-case stx ()
[(define-serializable name body ...)
#`(begin
(struct name body ...)
(define-struct-updaters name)
(hash-set! entity-structs (symbol->string 'name)
#,(datum->syntax #'name
(let [(datum-name (syntax->datum #'name))]
(string->symbol (string-append "struct:" (symbol->string datum-name)))))))]))
(define-syntax (checked-guard stx)
(syntax-case stx []
[(_ [(args . preds) ...] body ...)
(let []
(define/with-syntax [n ...]
(datum->syntax #'[args ...]
(~> #'[args ...]
syntax->list
length
range)))
#`(lambda [args ... name]
(unless (preds args)
(raise-argument-error name
(with-output-to-string
(lambda []
(write 'preds)))
n
args ...)) ...
body ...))]))
(define (bytes-empty? byte-stream)
(equal? #"" byte-stream))
(define (split-by lst n)
(if (not (empty? lst))
(cons (take lst n) (split-by (drop lst n) n))
'()))
(define (take-up-to l n)
(let [(size (length l))]
(if (> size n)
(take l n)
(take l size))))
(module interfaces racket
(provide
serializable?
byteable?
identifiable?
gen:serializable
gen:byteable
gen:identifiable
(contract-out
[give-identifier (-> identifiable? string?)]
[serialize (->* (serializable?) (#:size integer?) (values natural? bytes?))]
[deserialize (-> serializable? bytes? serializable?)]
[from-bytes (-> byteable? bytes? serializable?)]
[to-byte-size (-> byteable? natural?)]))
(require racket/generic racket/contract)
(define-generics identifiable #:requires [give-identifier]
(give-identifier identifiable))
(define-generics serializable #:requires [serialize deserialize]
(serialize serializable #:size (size))
(deserialize serializable byte-stream))
(define-generics byteable #:requires [from-bytes to-byte-size]
(from-bytes byteable byte-stream)
(to-byte-size byteable)))
(module+ hashable
(provide
(contract-out
[deserialize-hash-list (-> serializable? natural? bytes? (values natural? list?))]
[serialize-hash-list (-> (listof (cons/c string? serializable?)) bytes?)]))
(require (submod ".." interfaces))
(define (deserialize-hash-list entity how-many byte-stream)
(inner-deserialize-hash-list entity how-many byte-stream 0 '()))
(define (inner-deserialize-hash-list entity how-many byte-stream consumed-bytes accumulator)
(define (deserialize-name more-bytes)
(let* [(name-size (integer-bytes->integer (subbytes more-bytes 0 4) #t))
(name (bytes->string/utf-8 (subbytes more-bytes 4 (+ 4 name-size))))]
(values (+ 4 name-size) name)))
(if (zero? how-many)
(values consumed-bytes accumulator)
(let []
(define-values [name-consumed name] (deserialize-name byte-stream))
(define entity-size (integer-bytes->integer (subbytes byte-stream name-consumed (+ name-consumed 4)) #t))
(define thing (deserialize entity (subbytes byte-stream (+ 4 name-consumed) (+ name-consumed entity-size 4))))
(inner-deserialize-hash-list
entity
(- how-many 1)
(subbytes byte-stream (+ 4 name-consumed entity-size))
(+ consumed-bytes name-consumed entity-size 4)
(append accumulator (list (cons name thing)))))))
(define (serialize-hash-list named-values-list)
(define (serialize-name name)
(let* [(name-bytes (string->bytes/utf-8 name))
(name-size (bytes-length name-bytes))
(serialized-name-size (integer->integer-bytes name-size 4 #t))]
(bytes-append serialized-name-size name-bytes)))
(~>
(map (lambda [named-value]
(let* [(name (car named-value))
(value (cdr named-value))]
(define-values [value-size serialized-value] (serialize value))
(bytes-append
(serialize-name name)
(integer->integer-bytes value-size 4 #t)
serialized-value)))
named-values-list)
(bytes-join _ #""))))