     (PersistentBytes/wrap (bytes/to-byte-array source))))
 
 
-(defn- resolve-hasher
-  "Resolves an algorithm designator to a hash function. Throws an exception on
-  invalid names or error."
-  [algorithm]
-  (cond
-    (nil? algorithm)
-      (throw (IllegalArgumentException.
-               "Cannot find hash function without algorithm name"))
-
-    (keyword? algorithm)
-      (if-let [hf (clojure.core/get digest/functions algorithm)]
-        hf
-        (throw (IllegalArgumentException.
-                 (str "Cannot map algorithm name " algorithm
-                      " to a supported hash function"))))
-
-    (ifn? algorithm)
-      algorithm
-
-    :else
-      (throw (IllegalArgumentException.
-               (str "Hash algorithm must be keyword name or direct function, got: "
-                    (pr-str algorithm))))))
-
-
-(defn checked-hasher
-  "Constructs a function for the given hash algorithm or function which checks
-  that the result is a `Multihash`."
-  [algorithm]
-  (let [hash-fn (resolve-hasher algorithm)]
-    (fn hasher
-      [source]
-      (let [id (hash-fn source)]
-        (when-not (instance? Multihash id)
-          (throw (RuntimeException.
-                   (str "Block identifier must be a Multihash, "
-                        "hashing algorithm returned: " (pr-str id)))))
-        id))))
-
-
 
 ;; ## Constructors
 

      (or (identical? this that)
          (when (identical? (class this) (class that))
            (let [that ^Block that]
              (and (= id     (.id     that))
                   (= size   (.size   that))
                   (= _attrs (._attrs that))))))))

  (hashCode
    [this]
    (hash [(class this) id size _attrs]))


  java.lang.Comparable

  (compareTo
    [this that]
    (compare [id size _attrs]
             [(:id that) (:size that)
              (when (identical? (class this) (class that))
                (._attrs ^Block that))]))


  clojure.lang.IObj

  (meta [this] _meta)

  (withMeta
    [this meta-map]
    (Block. id size content _attrs meta-map))


  ; TODO: IKeywordLookup?
  clojure.lang.ILookup

  (valAt
    [this k]
    (.valAt this k nil))

  (valAt
    [this k not-found]
    (case k
      :id id
      :size size
      (get _attrs k not-found)))


  clojure.lang.IPersistentMap

  (count
    [this]
    (+ 2 (count _attrs)))

  (empty
    [this]
    (Block. id size nil nil _meta))

  (cons
    [this element]
    (cond
      (instance? java.util.Map$Entry element)
        (let [^java.util.Map$Entry entry element]
          (.assoc this (.getKey entry) (.getValue entry)))
      (vector? element)
        (.assoc this (first element) (second element))
      :else
        (loop [result this
               entries element]
          (if (seq entries)
            (let [^java.util.Map$Entry entry (first entries)]
              (recur (.assoc result (.getKey entry) (.getValue entry))
                     (rest entries)))
            result))))

  (equiv
    [this that]
    (.equals this that))

  (containsKey
    [this k]
    (not (identical? this (.valAt this k this))))

  (entryAt
    [this k]
    (let [v (.valAt this k this)]
      (when-not (identical? this v)
        (clojure.lang.MapEntry. k v))))

  (seq
    [this]
    (seq (concat [(clojure.lang.MapEntry. :id id)
                  (clojure.lang.MapEntry. :size size)]
                 _attrs)))

  (iterator
    [this]
    (clojure.lang.RT/iter (seq this)))

  (assoc
    [this k v]
    (case k
      (:id :size :content)
        (throw (IllegalArgumentException.
                 (str "Block " k " cannot be changed")))
      (Block. id size content (assoc _attrs k v) _meta)))

  (without
    [this k]
    (case k
      (:id :size :content)
        (throw (IllegalArgumentException.
                 (str "Block " k " cannot be changed")))
      (Block. id size content (not-empty (dissoc _attrs k)) _meta))))


(defmethod print-method Block

  [^Block block start end]
  (let [content (.content block)]
    (when-not content
      (throw (IOException. (str "Cannot open empty block " block))))
    (if (or start end)
      (read-range content start end)
      (read-all content))))



;; ## Content Functions

(defn persistent-bytes?
  "True if the argument is a persistent byte array."
  [x]
  (instance? PersistentBytes x))


(defn byte-content?
  "True if the block has content loaded into memory as persistent bytes."
