1 Introduction
1.1 Overview
std.lib.bin is part of the standard foundation library set. This page collects the public API reference for the namespace.
2 Walkthrough
2.1 NIO buffers
std.lib.bin.buffer creates typed NIO buffers. buffer is the general constructor; convenience functions like int-buffer and double-buffer are also available.
create and write to a buffer
^{:refer std.lib.bin.buffer/buffer :added "3.0"}
(buffer 16)
=> java.nio.ByteBuffer
^{:refer std.lib.bin.buffer/int-buffer :added "3.0"}
(int-buffer 4 {:direct true :endian :little})
=> java.nio.IntBuffer
^{:refer std.lib.bin.buffer/buffer-write :added "3.0"}
(let [^java.nio.ByteBuffer b (buffer 16)]
(buffer-write b (int-array [1 2 3 4]))
[(.get b 3) (.get b 7) (.get b 11) (.get b 15)])
=> [1 2 3 4]
read from a buffer
^{:refer std.lib.bin.buffer/buffer-read :added "3.0"}
(let [buf (buffer 4)
out (int-array 1)]
(.put ^java.nio.ByteBuffer buf 3 (byte 1))
(buffer-read buf out)
(first out))
=> 1
2.2 Binary conversions
std.lib.bin.type converts values between bit strings, bit sequences, bit sets, byte arrays, and numbers.
convert between binary representations
^{:refer std.lib.bin.type/bitseq :added "3.0"}
(btype/bitseq (byte-array [49]))
=> [1 0 0 0 1 1]
^{:refer std.lib.bin.type/bitstr :added "3.0"}
(btype/bitstr (byte-array [49]))
=> "100011"
^{:refer std.lib.bin.type/number :added "3.0"}
(btype/number "100011")
=> 49
^{:refer std.lib.bin.type/bytes :added "3.0"}
(-> (btype/bytes "100011")
seq)
=> [49]
3 API
- bitseq
- bitset
- bitstr
- buffer
- buffer-read
- buffer-write
- byte-buffer
- bytes
- char-buffer
- double-buffer
- float-buffer
- input-stream
- int-buffer
- long-buffer
- number
- output-stream
- short-buffer
v 3.0
(definvoke bitseq
[:compose {:val (comp protocol.binary/-to-bitseq prepare-binary)
:arglists '([obj])}])
link
(binary/bitseq (byte-array [49])) => [1 0 0 0 1 1]
v 3.0
(definvoke bitset
[:compose {:val (comp protocol.binary/-to-bitset prepare-binary)
:arglists '([obj])}])
link
(-> (binary/bitset "100011") (bitset-to-bitseq)) => [1 0 0 0 1 1]
v 3.0
(definvoke bitstr
[:compose {:val (comp protocol.binary/-to-bitstr prepare-binary)
:arglists '([obj])}])
link
(binary/bitstr (byte-array [49])) => "100011"
buffer ^
[len-or-elems] [len-or-elems {:keys [type direct endian convert wrap], :or {type :byte, direct false, endian +endian-native+, convert true, wrap false}}]
either creates or wraps a byte buffer of a given type
v 3.0
(defn buffer
([len-or-elems]
(buffer len-or-elems {}))
([len-or-elems {:keys [type direct endian convert wrap]
:or {type :byte
direct false
endian +endian-native+
convert true
wrap false}}]
(let [[len elems] (if (number? len-or-elems)
[len-or-elems nil]
[(count len-or-elems) len-or-elems])]
(if wrap
((get-in +buffer-records+ [type :wrap]) elems)
(buffer-create type elems len direct endian convert)))))
link
(buffer 10) => java.nio.ByteBuffer (buffer 10 {:type :float :convert false}) => java.nio.ByteBuffer (buffer 10 {:type :float :direct true}) => java.nio.FloatBuffer (def farr (float-array [1 2 3 4])) (= (.array ^java.nio.FloatBuffer (buffer farr {:type :float :wrap true})) farr) => true (not= (.array ^java.nio.FloatBuffer (buffer farr {:type :float})) farr) => true
v 3.0
(defn buffer-read
([^java.nio.Buffer buff]
(cond (.hasArray buff)
(.array buff)
:else
(let [len (.capacity buff)
arr ((buffer-primitive buff :array-fn) len)]
(buffer-read buff arr))))
([^java.nio.Buffer buff arr]
(let [comp (class/class:array-component (type arr))
ctype (class/primitive comp :type)]
(cond (instance? (get-in +buffer-records+ [ctype :buffer])
buff)
(do (doto buff
(.rewind)
(buffer-get arr))
arr)
(instance? ByteBuffer buff)
(recur (buffer-convert buff ctype) arr)
:else
(throw (ex-info "Incompatible buffer and array" {:buffer {:type (type buff)}
:array {:type ctype}}))))))
link
(def -buf- (buffer 4)) (def -out- (int-array 1)) (do (.put ^java.nio.ByteBuffer -buf- 3 (byte 1)) (buffer-read -buf- -out-) (first -out-)) => 1
v 3.0
(defn buffer-write
([^java.nio.Buffer buff arr]
(let [comp (class/class:array-component (type arr))
ctype (class/primitive comp :type)]
(cond (instance? (get-in +buffer-records+ [ctype :buffer])
buff)
(doto buff
(buffer-put arr)
(.rewind))
(instance? ByteBuffer buff)
(recur (buffer-convert buff ctype) arr)
:else
(throw (ex-info "Incompatible buffer and array" {:buffer {:type (type buff)}
:array {:type ctype}}))))))
link
(def ^java.nio.ByteBuffer -buf- (buffer 16)) (buffer-write -buf- (int-array [1 2 3 4])) [(.get -buf- 3) (.get -buf- 7) (.get -buf- 11) (.get -buf- 15)] => [1 2 3 4]
byte-buffer ^
[len-or-elems] [len-or-elems {:keys [type direct endian convert], :as opts}]
generated
;; generated at runtime, no single source form
link
(byte-buffer 5 {:direct true :endian :little}) => java.nio.ByteBuffer
v 3.0
(definvoke bytes
[:compose {:val (comp protocol.binary/-to-bytes prepare-binary)
:arglists '([obj])}])
link
(-> (binary/bytes "100011") (seq)) => [49]
char-buffer ^
[len-or-elems] [len-or-elems {:keys [type direct endian convert], :as opts}]
generated
;; generated at runtime, no single source form
link
(char-buffer 5 {:direct true :endian :little}) => java.nio.CharBuffer
double-buffer ^
[len-or-elems] [len-or-elems {:keys [type direct endian convert], :as opts}]
generated
;; generated at runtime, no single source form
link
(double-buffer 5 {:direct true :endian :little}) => java.nio.DoubleBuffer
float-buffer ^
[len-or-elems] [len-or-elems {:keys [type direct endian convert], :as opts}]
generated
;; generated at runtime, no single source form
link
(float-buffer 5 {:direct true :endian :little}) => java.nio.FloatBuffer
v 3.0
(definvoke ^InputStream input-stream
[:compose {:val (comp protocol.binary/-to-input-stream prepare-input-stream)
:arglists '([obj])}])
link
(input-stream 9223372036854775808N) => java.io.ByteArrayInputStream
int-buffer ^
[len-or-elems] [len-or-elems {:keys [type direct endian convert], :as opts}]
generated
;; generated at runtime, no single source form
link
(int-buffer 5 {:direct true :endian :little}) => java.nio.IntBuffer
long-buffer ^
[len-or-elems] [len-or-elems {:keys [type direct endian convert], :as opts}]
generated
;; generated at runtime, no single source form
link
(long-buffer 5 {:direct true :endian :little}) => java.nio.LongBuffer
v 3.0
(definvoke number
[:compose {:val (comp protocol.binary/-to-number prepare-binary)
:arglists '([obj])}])
link
(binary/number "100011") => 49 (-> (binary/number (byte-array [78 45 34 -12 45 34 56])) (binary/bitstr) (binary/bitset) (binary/bytes) (seq)) => [78 45 34 -12 45 34 56]
4 std.lib.bin: A Comprehensive Summary
The std.lib.bin namespace, along with its sub-namespaces std.lib.bin.buffer and std.lib.bin.type, provides a comprehensive set of utilities for working with binary data in Clojure. This module focuses on efficient manipulation of byte buffers, conversion between various binary representations (bit strings, bit sequences, bit sets, numbers, byte arrays), and handling I/O streams and channels for binary data.
4.1 std.lib.bin (Main Namespace)
This namespace primarily acts as an aggregator, re-exporting key functions from its sub-namespaces std.lib.bin.buffer and std.lib.bin.type. It simplifies access to the binary manipulation capabilities by providing a unified interface.
Key Re-exported Functions:
- From
std.lib.bin.buffer:buffer,buffer-read,buffer-write, and type-specific buffer creation functions likebyte-buffer,char-buffer,short-buffer,int-buffer,long-buffer,float-buffer,double-buffer.n* Fromstd.lib.bin.type:input-stream,output-stream,bitseq,bitstr,bitset,bytes,number.
4.2 std.lib.bin.buffer (NIO Buffer Manipulation)
This sub-namespace provides tools for creating, manipulating, and converting Java NIO ByteBuffer and its type-specific views (e.g., IntBuffer, DoubleBuffer). It emphasizes direct memory manipulation and control over byte order (endianness).
Core Concepts:
- NIO Buffers: Leverages Java's
java.niopackage for efficient, direct memory access to binary data.n Endianness: Explicit control overByteOrder(big-endian or little-endian) for multi-byte data types.n Type-Specific Buffers: Supports creating and working with buffers for various primitive types (byte, char, short, int, long, float, double).
Key Functions:
byte-order: Converts a keyword (:little,:big) to ajava.nio.ByteOrderobject.nbuffer: The primary function for creating or wrapping NIO buffers. It allows specifying the buffer type (:byte,:int, etc.), whether it's direct or heap-allocated, endianness, and if it should convert to a type-specific view.n Type-specific buffer creation functions (e.g.,byte-buffer,double-buffer): Convenience wrappers aroundbufferfor specific primitive types.nbuffer-convert: Converts aByteBufferto a type-specific buffer (e.g.,DoubleBuffer).nbuffer-type: Returns metadata (e.g.,:type,:array-fn) about the primitive type associated with a given buffer class.nbuffer-primitive: Similar tobuffer-type, but works with a buffer instance.nbuffer-put: Writes a primitive array into a buffer.nbuffer-get: Reads data from a buffer into a primitive array.nbuffer-write: Writes a primitive array into aByteBuffer, handling type conversion if necessary.n*buffer-read: Reads data from a buffer into a primitive array, handling type conversion.
4.3 std.lib.bin.type (Binary Data Conversion and I/O)
This sub-namespace focuses on converting data between various binary representations and providing unified interfaces for binary I/O (streams and channels). It extends the std.protocol.binary/IBinary and std.protocol.binary/IByteSource/IByteSink/IByteChannel protocols to many common Java types.
Core Concepts:
IBinaryProtocol: Defines a set of functions for converting an object to different binary forms:bitstr(binary string),bitseq(sequence of 0s and 1s),bitset(java.util.BitSet),bytes(byte array), andnumber(numeric representation).nIByteSource/IByteSink/IByteChannelProtocols: Provide a unified way to getInputStream,OutputStream, orByteChannelfrom various data sources (e.g.,File,URL,ByteBuffer,byte[]).n Supported Formats: The module explicitly supports conversion for: bit strings, bit sequences, bit sets, numbers (Long, BigInt), byte arrays,InputStream,ByteBuffer,File,Path,Channel,URL,URI.
Key Functions:
bitstr-to-bitseq,bitseq-to-bitstr: Convert between binary strings and sequences.nbitseq-to-number,long-to-bitseq: Convert between binary sequences and numbers (handling large numbers withBigInt).nbitseq-to-bitset,bitset-to-bitseq: Convert between binary sequences andBitSet.nbitset-to-bytes,bytes-to-bitset: Convert betweenBitSetand byte arrays.nbitstr?: Checks if a string is a valid binary string (contains only '0' and '1').ninput-stream: Creates anInputStreamfrom various binary representations.noutput-stream: Creates anOutputStreamfrom various binary representations.nchannel: Creates aByteChannelfrom various binary representations.nbitstr,bitseq,bitset,bytes,number(definvoke functions): These are the primary entry points for converting any supported object into its respective binary representation, leveraging theIBinaryprotocol.
4.4 Usage Pattern:
This module is essential for any application requiring low-level binary data handling, network communication, file I/O, or cryptographic operations where precise control over data representation and efficient processing are critical. It abstracts away much of the boilerplate Java interop for NIO buffers and binary conversions, providing a more idiomatic Clojure interface.
Usage Pattern: example
;; Example: Creating and writing to a ByteBuffer
(require '[std.lib.bin :as bin])
(def my-buffer (bin/int-buffer 4)) ; Creates an IntBuffer with capacity 4
(bin/buffer-write my-buffer (int-array [10 20 30 40]))
;; Example: Converting a number to a bit sequence and then to bytes
(require '[std.lib.bin.type :as btype])
(def num-val 49)
(def bit-seq (btype/bitseq num-val)) ; => [1 0 0 0 1 1]
(def byte-arr (btype/bytes num-val)) ; => byte-array with [49]