 (ns blocks.core
-  "Block storage protocol and utility functions.
+  "Block storage protocol and utilities. Functions which may cause IO to occur
+  are marked with bangs; for example `(read! \"foo\")` doesn't have
+  side-effects, but `(read! some-input-stream)` will consume bytes from the
+  stream.
 
   When blocks are returned from a block store, they may include 'stat' metadata
-  about the blocks:
+  about the blocks, including:
 
   - `:stored-at`   time block was added to the store
   - `:origin`      resource location for the block


;; ## Utility Functions

(defn select-hashes
  "Selects multihash identifiers from a sequence based on some criteria.

  Available options:

  - `:algorithm`  only return hashes using this algorithm
  - `:after`      start enumerating ids lexically following this string
  - `:limit`      return at most 'limit' hashes
  "
  [opts ids]
  ; TODO: this is an awkward way to search the store, think of a better approach
  (let [{:keys [algorithm prefix encoder], :or {encoder multihash/hex}} opts
        after (:after opts prefix)]
    (cond->> ids
      algorithm  (filter #(= algorithm (:algorithm %)))
      after      (drop-while #(pos? (compare after (encoder %))))
      prefix     (take-while #(.startsWith ^String (encoder %) prefix)))))


(defn scan-size

(defprotocol BlockStore
  "Protocol for content-addressable storage keyed by multihash identifiers."

  (stat
    [store id]
    "Returns a map with an `:id` and `:size` but no content. The returned map
    may contain additional data like the date stored. Returns nil if the store
    does not contain the identified block.")

  (-list
    [store opts]
    "Enumerates the ids of the stored blocks with some filtering options. See
