Today, I spent a bit of time trying to figure out a way to efficiently compute message digest for Quicklisp. After confirming that java.security.MessageDigest implements the required digests, I noticed we didn't have a way to easily get at the underlying Java byte[] array in (SIMPLE-VECTOR (UNSIGNED-BYTE 8)). So, I patched the underlying Java code as attached, and wrote the following routine:
(defun sha-256 (path) (let ((buffer (make-array 8192 :element-type '(unsigned-byte 8)) (digest (jstatic "getInstance" "java.security.MessageDigest" "SHA-256"))) (with-open-file (in path :element-type '(unsigned-byte 8)) (loop :for bytes = (read-sequence buffer in) :while (plusp bytes) :do (jcall-raw "update" digest (make-immediate-object buffer) 0 bytes)) (jcall "digest" digest)))))
But then I noticed that MAKE-IMMEDIATE-OBJECT calls JOBJECT-LISP-VALUE which makes no conceptual sense. The doc for MAKE-IMMEDIATE-OBJECT reads "[a]ttempts to coerce a given Lisp object into a java-object" while the doc JOBJECT-LISP-VALUE reads "Attempts to coerce JAVA-OBJECT into a Lisp object". This seems wrong here, but I don't understand how exactly. I think we need to distinguish three types of values here: JAVA-OBJECT, LispObject, and the "raw" value of the Java. How should we really structure our Java FFI here?
With my patch, for an underlying lisp value of type (SIMPLE-VECTOR (UNSIGNED-BYTE 8)), both MAKE-IMMEDIATE-OBJECT and JOBJECT-LISP-OBJECT return the byte[] array. I would think that MAKE-IMMEDIATE-OBJECT should just do this, which JOBJECT-LISP-OBJECT should .... return an error if its argument isn't of type JAVA-OBJECT? I don't know. I am confused.
Can someone help me understand the right way forward here?