八発白中

技術ブログ、改め雑記

Day 6: circular-streams

これは fukamachi products advent calendar 2016 の6日目の記事です。

今日はcircular-streamsについて話します。

circular-streamsとは

これまでのプロダクトとは違ってcircular-streamsは裏側で使われているライブラリなので知らない人も多いと思います。

Common Lispのストリームはreadを始めて一方向に読み込みを進めます。一度readしたものは基本的に戻すことはできません。ストリームの終端まで来るとEOFになります。

この性質は他の言語でも一般的なものだと思われます。けれど、複数のコードから一つのストリームを共有するような場合に問題になります。なぜなら先に走ったコードがストリームを読み終わってしまうと、もう一方がストリームを読みに行ってもEOFが帰ってきて読み込めないからです。

これはClackのアーキテクチャにとっては不利な仕様です。

複数のミドルウェアでリクエストボディのストリームを共有していると、前のミドルウェアが全部ストリームを読んでしまった場合にbody-parametersを読めなくなってしまいます。

circular-streamsはこの問題を解決します。

make-circular-streamsでストリームをラップすると、EOFまで読んだあとにまた再び最初からreadすることができます。内部的にバッファを持っており、一度読んだものをまるでストリームから読んだかのように見せます。

(defparameter *stream*
              (flex:make-in-memory-input-stream
               #(72 101 108 108 111)))

(defparameter *circular-stream*
              (make-circular-stream *stream*))

(read-char *circular-stream*)          ;=> #\H
(read-char *circular-stream*)          ;=> #\e
(read-char *circular-stream*)          ;=> #\l
(read-char *circular-stream*)          ;=> #\l
(read-char *circular-stream*)          ;=> #\o
(read-char *circular-stream* nil :eof) ;=> :eof
(read-char *circular-stream*)          ;=> #\H

面白いでしょう?

おわりに

circular-streamsはGitHubで公開されており、現在Starはたったの2です。寂しい。

明日のアドベントカレンダーは7日目のcl-dbiについてです。お楽しみに。