Skip to content

Commit bea74d6

Browse files
committed
fix some issues and add 'precache-conversions', fixes #10 #12 #13
1 parent 15e546f commit bea74d6

File tree

3 files changed

+48
-28
lines changed

3 files changed

+48
-28
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ push
1414
dump*
1515
/doc
1616
DS_Store
17+
.nrepl*

src/byte_streams.clj

+38-26
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343

4444
(defprotocol ByteSource
4545
(take-bytes! [_ n options] "Takes `n` bytes from the byte source."))
46-
46+
4747
(defprotocol ByteSink
4848
(send-bytes! [_ bytes options] "Puts `bytes` in the byte sink."))
4949

@@ -146,13 +146,13 @@
146146
(cond
147147
(and (class? a) (class? b))
148148
(.isAssignableFrom ^Class b a)
149-
149+
150150
(and (protocol? b) (class? a))
151151
(class-satisfies? b a)
152-
152+
153153
(and (seq-of? a) (seq-of? b))
154154
(assignable? (second a) (second b))
155-
155+
156156
:else
157157
(= a b))))
158158

@@ -221,7 +221,7 @@
221221
java.io.Closeable
222222
(close [_]
223223
(close-fn))
224-
224+
225225
clojure.lang.Sequential
226226
clojure.lang.ISeq
227227
clojure.lang.Seqable
@@ -273,13 +273,13 @@
273273
(fn [[a b :as a+b]]
274274
(if-let [f (get-in @src->dst->conversion a+b)]
275275
f
276-
276+
277277
;; implicit (seq-of a) -> (seq-of b) conversion
278278
(if-let [f (when (every? seq-of? a+b)
279279
(get-in @src->dst->conversion (map second a+b)))]
280280
(fn [x options]
281281
(map #(f % options) x))
282-
282+
283283
;; this shouldn't ever happen, but let's have a decent error message all the same
284284
(throw
285285
(IllegalStateException.
@@ -289,7 +289,7 @@
289289
(let [close-fns (atom (tuple))
290290
result (reduce
291291
(fn [x f]
292-
292+
293293
;; keep track of everything that needs to be closed once the bytes are exhausted
294294
(when (closeable? x)
295295
(swap! close-fns conj #(close x)))
@@ -298,7 +298,7 @@
298298
fns)]
299299
(if-let [close-fn (when-let [fns (seq @close-fns)]
300300
#(doseq [f fns]
301-
(f)))]
301+
(f)))]
302302
(if (sequential? result)
303303
(closeable-seq result true close-fn)
304304
(do
@@ -392,6 +392,15 @@
392392
^long [x dst]
393393
(memoized-cost (type-descriptor x) dst)))
394394

395+
(defn precache-conversions
396+
"Walk the graph of conversions, making all subsequent conversions reliably fast."
397+
[]
398+
(->> @src->dst->conversion
399+
(mapcat #(map list (repeat %) (possible-conversions %)))
400+
distinct
401+
(map #(apply conversion-path %))
402+
dorun))
403+
395404
;;; transfer
396405

397406
(defn- default-transfer [source sink {:keys [chunk-size] :or {chunk-size 1024} :as options}]
@@ -416,28 +425,28 @@
416425
first
417426
second)]
418427
(cond
419-
428+
420429
(and src' dst')
421430
(let [f (get-in @src->dst->transfer [src' dst'])]
422431
(fn [source sink options]
423-
(let [source' (convert source src')
424-
sink' (convert sink dst')]
432+
(let [source' (convert source src' options)
433+
sink' (convert sink dst' options)]
425434
(f source' sink' options)
426435
(doseq [x [source sink source' sink']]
427436
(when (closeable? x)
428437
(close x))))))
429-
438+
430439
(and
431440
(conversion-path src ByteSource)
432441
(conversion-path dst ByteSink))
433442
(fn [source sink options]
434-
(let [source' (convert source ByteSource)
435-
sink' (convert sink ByteSink)]
443+
(let [source' (convert source ByteSource options)
444+
sink' (convert sink ByteSink options)]
436445
(default-transfer source' sink' options)
437446
(doseq [x [source sink source' sink']]
438447
(when (closeable? x)
439448
(close x)))))
440-
449+
441450
:else
442451
nil)))))
443452

@@ -589,7 +598,7 @@
589598
(let [^ByteBuffer buf (first s)]
590599
(.mark buf)
591600
(.write sink buf)
592-
(.reset buf)
601+
(.reset buf)
593602
(recur (rest s)))))
594603
(.close sink))
595604
source))
@@ -604,7 +613,7 @@
604613
(close source))
605614
options))
606615

607-
;; input-stream => reader
616+
;; input-stream => reader
608617
(def-conversion [InputStream Reader]
609618
[input-stream {:keys [encoding] :or {encoding "utf-8"}}]
610619
(BufferedReader. (InputStreamReader. input-stream ^String encoding)))
@@ -654,7 +663,7 @@
654663
(let [remaining (- (.size fc) offset)]
655664
(lazy-seq
656665
(cons
657-
(.map fc
666+
(.map fc
658667
(if writable?
659668
FileChannel$MapMode/READ_WRITE
660669
FileChannel$MapMode/READ_ONLY)
@@ -696,7 +705,7 @@
696705
(let [^FileChannel fc (convert file ReadableByteChannel options)]
697706
(try
698707
(loop [idx 0]
699-
(let [n (.transferTo fc channel idx chunk-size)]
708+
(let [n (.transferTo fc idx chunk-size channel)]
700709
(when (pos? n)
701710
(recur (+ idx n)))))
702711
(finally
@@ -705,12 +714,15 @@
705714
(def-transfer [InputStream OutputStream]
706715
[input-stream output-stream {:keys [chunk-size] :or {chunk-size 4096} :as options}]
707716
(let [ary (clojure.core/byte-array chunk-size)]
708-
(loop []
709-
(let [n (.read ^InputStream input-stream ary)]
710-
(when (pos? n)
711-
(.write ^OutputStream output-stream ary 0 n)
712-
(.flush ^OutputStream output-stream)
713-
(recur))))))
717+
(try
718+
(loop []
719+
(let [n (.read ^InputStream input-stream ary)]
720+
(when (pos? n)
721+
(.write ^OutputStream output-stream ary 0 n)
722+
(.flush ^OutputStream output-stream)
723+
(recur))))
724+
(finally
725+
(.close ^OutputStream output-stream)))))
714726

715727
;;; protocol extensions
716728

test/byte_streams_test.clj

+9-2
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,18 @@
5555

5656
(deftest test-transfer
5757
(doseq [dst (possible-conversions text)]
58-
(let [file (temp-file)]
58+
(let [file (temp-file)
59+
file' (temp-file)]
5960
(transfer (convert text dst) dev-null)
6061
(transfer (convert text dst) file {:chunk-size 128})
6162
(is (= text (to-string file)))
62-
(is (= text (to-string (to-byte-buffers file {:chunk-size 128})))))))
63+
(transfer (convert text dst) file {:chunk-size 128, :append? false})
64+
(is (= text (to-string file)))
65+
(is (= text (to-string (to-byte-buffers file {:chunk-size 128}))))
66+
67+
(transfer file file')
68+
(is (= text (to-string file')))
69+
(is (= text (to-string (to-byte-buffers file' {:chunk-size 128})))))))
6370

6471
;;;
6572

0 commit comments

Comments
 (0)