Core API - moxaj/mikron GitHub Wiki

Most public functions reside in the mikron.runtime.core namespace. In the scope of this document, consider this namespace implicitly loaded and aliased to mikron.

Schema definitions

mikron/schema

Reifies a schema definition.

Signature

(mikron/schema schema-name schema-def & args)

  • schema-name:
    • syntax: an optional qualified keyword
    • semantics: the name of the schema, allows self-reference
  • schema-def: a schema definition, see Schema DSL
  • & args: a key-value sequence, see Schema options
  • return value:
    • syntax: an instance of mikron/Schema
    • semantics: a reified schema compiled from the schema definition
Examples
;; Inline schema
(mikron/schema :int)
;; => <reified schema instance>

;; Inline schema with self-reference
(mikron/schema ::x [:tuple [:int [:optional ::x]]])
;; => <reified schema instance>

mikron/defschema

Reifies a schema definition and registers it globally with the given name.

Signature

(mikron/defschema schema-name schema-def & args)

  • schema-name:
    • syntax: a qualified keyword
    • semantics: the name of the schema
  • schema-def: a schema definition, see Schema DSL
  • & args: a key-value sequence, see Schema options
  • return value: schema-name
Examples
;; Simple reference
(mikron/defschema ::x :int)
;; => :user/x

(mikron/defschema ::y [:vector ::x])
;; => :user/y

;; Circular reference (referenced schemas are resolved at runtime)
(mikron/defschema ::u [:tuple [:int [:optional ::v]]])
;; => :user/u

(mikron/defschema ::v [:tuple [:int [:optional ::u]]])
;; => :user/v

Both mikron/schema and mikron/defschema are macros, therefore receive their arguments unevaluated, thus the following example will throw:

(mikron/schema [:tuple (vec (repeat 16 :byte))])
;; => <exception>

To work around this, you can either define and invoke your own macro:

(defmacro foo []
  `(mikron/schema [:tuple [~@(repeat 16 :byte)]]))

(foo)
;; => <reified schema instance>

... or make use of an e̸xp͏͏̀e͟r͜͝҉i̛͟m͏̕͟e̶nta̧l feature which allows you to evaluate parts of the macro input by marking them with an ^eval tag:

(mikron/schema [:tuple ^eval (vec (repeat 16 :byte))])
;; => <reified schema instance>

Note however that in self-hosted ClojureScript, vars referenced in the marked expressions must be defined in seperate compilation stages (ie. namespaces).

Packing and unpacking

mikron/pack

Serializes a value.

Signature

(mikron/pack schema value)

  • schema: either
    • a reified schema (see Case A and Case B)
    • a qualified keyword to which a schema was registered via mikron/defschema (see Case C)
  • value: a value to serialize, must conform to schema, may be wrapped in mikron/DiffedValue (see Diffing and undiffing)
  • return value:
    • syntax: an instance of byte[] (Clojure) or ArrayBuffer (ClojureScript)
    • semantics: value serialized to a binary value
Examples
;; Case A (not preferred: other schemas cannot reference it)
(def x (mikron/schema :int))
;; => #'user.x

(mikron/pack x 10)
;; => <binary value>

;; Case B (not preferred: inlined)
(mikron/pack (mikron/schema :int) 10)
;; => <binary value>

;; Case C (preferred)
(mikron/defschema ::x :int)
;; => :user/x

(mikron/pack ::x 10)
;; => <binary value>

;; Invalid value
(mikron/pack ::x "10")
;; => <exception>
Notes

Not thread safe. If you wish to run multiple packs in parallel, use mikron/allocate-buffer and mikron/with-buffer.


mikron/unpack

Deserializes a serialized value.

Signature

(mikron/unpack schema binary)

  • schema: same as in mikron/pack
  • binary:
    • syntax: a binary value (an instance of byte[] (Clojure) or ArrayBuffer (ClojureScript))
    • semantics: the value from which to reconstruct a value conforming to schema
  • return value:
    • syntax: a value which conforms to schema or :mikron/invalid
    • semantics: the value deserialized from binary (potentionally wrapped in DiffedValue, see Packing and unpacking), or :mikron/invalid if any exception was thrown while deserializing
Examples
(mikron/defschema ::x :int)
;; => :user/x

(->> 10
     (mikron/pack ::x)
     (mikron/unpack ::x))
;; => 10

(->> true
     (mikron/pack (schema :boolean))
     (mikron/unpack ::x))
;; => :mikron/invalid

mikron/allocate-buffer

Allocates a new buffer.

Signature

(mikron/allocate-buffer size)

  • size:
    • syntax: a non-negative integer
    • semantics: the size of the buffer in bytes
  • return value:
    • syntax: an instance of mikron.buffer/MikronBuffer
    • semantics: the allocated buffer
Examples
(mikron/allocate-buffer 10000)
;; => <buffer instance>

mikron/with-buffer

Sets the buffer instance used by mikron/pack and evaluates each instruction in its dynamic scope.

Signature

(mikron/with-buffer buffer & body)

  • buffer:
    • syntax: an instance of mikron.buffer/MikronBuffer
    • semantics: the buffer to use in subsequent mikron/pack calls
  • & body: a sequence expressions
  • return value: the value of the last expression in & body
Examples
(def buffer (mikron/allocate-buffer 10000))
;; => #'user/buffer

(mikron/with-buffer buffer
  (mikron/pack (mikron/schema :int) 10))
;; => <binary>

mikron/set-byte-buffer-factory!

Sets the byte buffer factory globally (for all threads). If, for whatever reason, you'd like to use your own mikron.buffer/IMikronByteBuffer implementation, call this once your application loads. All subsequent buffer allocations (via mikron/allocate-buffer) or wraps (via mikron/unpack) will use the current byte buffer factory.

Signature

(mikron/set-byte-buffer-factory! byte-buffer-factory)

  • byte-buffer-factory:
    • syntax: an instance of mikron.buffer/MikronByteBufferFactory
    • semantics: the byte buffer factory to use
  • return value: undefined
Examples
;; Define our custom byte buffer implementation
(deftype CustomByteBuffer [...]
  mikron.buffer/IMikronByteBuffer
  ...)
;; => <CustomByteBuffer type>

;; Define a factory implementation which can instantiate our byte buffer implementation
(deftype CustomByteBufferFactory [...]
  mikron.buffer/IMikronByteBufferFactory
  (-allocate ...)
  (-wrap ...))
;; => <CustomByteBufferFactory type>

;; Set the byte buffer factory globally
(mikron/set-byte-buffer-factory! (->CustomByteBufferFactory ...))
;; => nil

;; Constructs a CustomByteBuffer instance via the `-allocate` method of the factory
(def buffer (mikron/allocate-buffer 10000))
;; => #'user/buffer

(def packed-value
  (mikron/with-buffer buffer
    (mikron/pack (schema :int) 10)))
;; => #'user/packed-value

;; Constructs a CustomByteBuffer instance via the `-wrap` method of the factory
(mikron/unpack (schema :int) packed-value)
;; => 10

Validation

mikron/valid?

Checks whether the given value conforms to the schema or not.

Signature

(mikron/valid? schema value)

  • schema: same as in mikron/pack
  • value:
    • syntax: anything
    • semantics: the value whose conformance to check
  • return value:
    • syntax: a boolean
    • true if value conforms to schema, false otherwise
Examples
(mikron/valid? (mikron/schema :int) 10)
;; => true

(mikron/valid? (mikron/schema :int) "cake")
;; => false

Random value generation

mikron/gen

Signature

(mikron/gen schema)

  • schema: same as in mikron/pack
  • return value:
    • syntax: a value which conforms to schema
    • semantics: the freshly generated value
Examples
(mikron/gen (mikron/schema :int))
;; => 10

Diffing and undiffing

All functions in this section depend on the :diff-paths options provided at the schema definition (see Schema options).


mikron/diff*

Calculates the difference (in some sense) between two values.

Signature

(mikron/diff* schema value-1 value-2)

Arguments
  • schema: same as in mikron/pack
  • value-1:
    • syntax: a value which conforms to schema
    • semantics: the old value
  • value-2:
    • syntax: a value which conforms to schema
    • semantics: the new value
  • return value:
    • syntax: a value whose parts are either equal to :mikron/nil or conform to the appropriate subschema
    • semantics: the value which represents the difference between value-1 and value-2
Examples
(mikron/defschema ::x :int :diff-paths true)

(mikron/diff* ::x 10 20)
;; => 20

(mikron/diff* ::x 10 10)
;; => :mikron/nil

mikron/undiff*

Restores a value from an original value and a calculated difference.

Signature

(mikron/undiff* schema value-1 value-2)

  • schema: same as in mikron/pack
  • value-1:
    • syntax: a value which conforms to schema
    • semantics: the old value
  • value-2:
    • syntax: a value whose parts are either :mikron/nil or conform to the appropriate subschema
    • semantics: the value which represents the difference between two values conforming to schema
  • return value:
    • syntax: a value which conforms to schema
    • semantics: the value reconstructed from value-1 and value-2
Examples
(mikron/defschema ::x :int :diff-paths true)

(->> 20
     (mikron/diff* ::x 10)
     (mikron/undiff* ::x 10))
;; => 20

(->> 10
     (mikron/diff* ::x 10)
     (mikron/undiff* ::x 10))
;; => 10

mikron/diff

Same as mikron/diff*, but also wraps the returned value in mikron/DiffedValue (which is an opaque container type to ease the consumption by mikron/pack).

Signature

(mikron/diff schema value-1 value-2)

  • schema: same as in mikron/pack
  • value-1:
    • syntax: a value which conforms to schema
    • semantics: the old value
  • value-2:
    • syntax: a value which conforms to schema
    • semantics: the new value
  • return value:
    • syntax: an instance of mikron/DiffedValue
    • semantics: the value which represents the difference between value-1 and value-2
Examples
(mikron/defschema ::x :int :diff-paths true)

(->> 20
     (mikron/diff ::x 10)
     (mikron/pack ::x))
;; => <binary value>

mikron/undiff

Same as mikron/undiff*, but expects the diffed value to be an instance of mikron/DiffedValue.

Signature

(mikron/undiff schema value-1 value-2)

  • schema: same as in mikron/pack
  • value-1:
    • syntax: a value which conforms to schema
    • semantics: the old value
  • value-2:
    • syntax: an instance of mikron/DiffedValue
    • semantics: the value which represents the difference between two values conforming to schema
  • return value:
    • syntax: a value which conforms to schema
    • semantics: the value reconstructed from value-1 and value-2
Examples
(mikron/defschema ::x :int :diff-paths true)

(->> 20
     (mikron/diff ::x 10)
     (mikron/pack ::x)
     (mikron/unpack ::x)
     (mikron/undiff ::x))
;; => 20
⚠️ **GitHub.com Fallback** ⚠️