Constructors for CVM cells and related type predicate functions.
Constructors for CVM cells and related type predicate functions.
Convert cells to Clojure types.
Sometimes lossy since some cells do not have equivalents in Clojure. For instance, addresses are converted to long. Recursive when it comes to collection.
Mainly useful for a deeper Clojure integration.
Convert cells to Clojure types. Sometimes lossy since some cells do not have equivalents in Clojure. For instance, addresses are converted to long. Recursive when it comes to collection. Mainly useful for a deeper Clojure integration.
Code execution in the Convex Virtual Machine, altering its state, and gaining insights.
The central entity of this namespace is the execution context created by ctx
. They embed a state
and allow
executing code to alter it.
All other functions revolve around contextes. While the design of a context is mostly immutable, whenever an altering function
is applied (eg. juice-set
) or code is handled in any way (eg. eval
), the old context must be discarded and only the
returned one should be used.
Cheap copies can be created using fork
.
Actions involving code (eg. compile
, exec
, ...) return a new context which holds either a result
or an exception
.
Those actions always consume juice
.
Given that a "cell" is the term reserved for CVM data and objects, execution consists of the following steps:
Step | Function | Does |
---|---|---|
1 | expand | cell -> canonical cell , applies macros |
2 | compile | canonical cell -> op , preparing executable code |
3 | exec | Executes compiled code |
Any cell can be applied safely to those functions, worse that can happen is nothing (e.g. providing an already compiled cell to
compile
).
If fine-grained control is not needed and if source is not compiled anyways, a simpler alternative is to use eval
which does
all the job.
Code execution in the Convex Virtual Machine, altering its state, and gaining insights. The central entity of this namespace is the execution context created by [[ctx]]. They embed a [[state]] and allow executing code to alter it. All other functions revolve around contextes. While the design of a context is mostly immutable, whenever an altering function is applied (eg. [[juice-set]]) or code is handled in any way (eg. [[eval]]), the old context must be discarded and only the returned one should be used. Cheap copies can be created using [[fork]]. Actions involving code (eg. [[compile]], [[exec]], ...) return a new context which holds either a [[result]] or an [[exception]]. Those actions always consume [[juice]]. Given that a "cell" is the term reserved for CVM data and objects, execution consists of the following steps: | Step | Function | Does | |------|-------------|-----------------------------------------------------| | 1 | [[expand]] | `cell` -> `canonical cell`, applies macros | | 2 | [[compile]] | `canonical cell` -> `op`, preparing executable code | | 3 | [[exec]] | Executes compiled code | Any cell can be applied safely to those functions, worse that can happen is nothing (e.g. providing an already compiled cell to [[compile]]). If fine-grained control is not needed and if source is not compiled anyways, a simpler alternative is to use [[eval]] which does all the job.
Etch is a fast, immutable, embedded database tailored for cells.
It can be understood as a data store where keys are hashes of the cells they point to.
Hence, the API is pretty simple. write
takes a cell and returns a hash while read
takes a hash and returns a cell (or nil if not found).
Most of the time, usage is even simpler by using root-write
and root-read
to persist
the state of a whole application at once (only new values are effectively written).
Data is retrieved semi-lazily. For instance, in the case of a large vector, only the the top structure of that vector is fetched. Elements are read from disk when actually accessed then cached using a clever system of soft references under the hood. This explains why data larger than memory can be retrieved and handled since the JVM can garbage-collect those soft references ; their value will be read from disk again if required. Nonetheless, users only deal with cells and all this process is completely transparent.
Attention, although this namespace is straightforward, one rule must be followed at all time: cells read from an instance can only be written back to that instance. In other words, one must never mix cells read from different instances with the intent of writing them anywhere. This will result in some of the data not being written. Everything, from cells to Etch, has been heavily optimized for Convex peers that only ever handle 1 instance at a time. It is fine using several stores in the same process as long as operations never cross-over.
Convex tooling, whenever an instance is needed, will always look for the instance associated
with the current thread (if any). The typical workflow is to call current-set
after open
:
(convex.db/current-set (convex.db/open "my/instance.etch"))
(convex.db/read (convex.db/write (convex.cell/* [:a :b 42])))
(convex.db/close)
If no instance is bound to the current thread explicitely, a temporary one is created whenever needed.
See global-set
for improving the workflow when an instance is needed in more than one thread.
When using a convex.cvm/ctx
, its state is initially hold in memory. After opening an Etch
instance and setting it as thread-local, this state can be retrieved at any point using convex.cvm/state
and persisted to disk since it is a cell. This renders that state garbage-collecteable as exposed
above. Of course, it is important not to close the instance before stopping all operations on that
context and its state.
Etch is a fast, immutable, embedded database tailored for cells. It can be understood as a data store where keys are hashes of the cells they point to. Hence, the API is pretty simple. [[write]] takes a cell and returns a hash while [[read]] takes a hash and returns a cell (or nil if not found). Most of the time, usage is even simpler by using [[root-write]] and [[root-read]] to persist the state of a whole application at once (only new values are effectively written). Data is retrieved semi-lazily. For instance, in the case of a large vector, only the the top structure of that vector is fetched. Elements are read from disk when actually accessed then cached using a clever system of soft references under the hood. This explains why data larger than memory can be retrieved and handled since the JVM can garbage-collect those soft references ; their value will be read from disk again if required. Nonetheless, users only deal with cells and all this process is completely transparent. Attention, although this namespace is straightforward, one rule must be followed at all time: cells read from an instance can only be written back to that instance. In other words, one must never mix cells read from different instances with the intent of writing them anywhere. This will result in some of the data not being written. Everything, from cells to Etch, has been heavily optimized for Convex peers that only ever handle 1 instance at a time. It is fine using several stores in the same process as long as operations never cross-over. Convex tooling, whenever an instance is needed, will always look for the instance associated with the current thread (if any). The typical workflow is to call [[current-set]] after [[open]]: ```clojure (convex.db/current-set (convex.db/open "my/instance.etch")) (convex.db/read (convex.db/write (convex.cell/* [:a :b 42]))) (convex.db/close) ``` If no instance is bound to the current thread explicitely, a temporary one is created whenever needed. See [[global-set]] for improving the workflow when an instance is needed in more than one thread. When using a [[convex.cvm/ctx]], its state is initially hold in memory. After opening an Etch instance and setting it as thread-local, this state can be retrieved at any point using [[convex.cvm/state]] and persisted to disk since it is a cell. This renders that state garbage-collecteable as exposed above. Of course, it is important not to close the instance before stopping all operations on that context and its state.
Quick helpers built on top of convex.cvm/eval
.
Systematically forks the used context before any operation so that it remains intact.
Notably useful when writing tests.
Quick helpers built on top of [[convex.cvm/eval]]. Systematically forks the used context before any operation so that it remains intact. Notably useful when writing tests.
Reading, parsing various kind of sources into CVX cells without any evaluation.
Attention, currently, functions that read only one cell fail when the input contains more than one. In the future, behavior should be improved. For instance, consuming cells one by one from a stream.
Also see the convex.write
namespace for the opposite idea.
Reading, parsing various kind of sources into CVX cells without any evaluation. Attention, currently, functions that read only one cell fail when the input contains more than one. In the future, behavior should be improved. For instance, consuming cells one by one from a stream. Also see the [[convex.write]] namespace for the opposite idea.
Provides an API for cells with classic convex.core
functions such as conj
.
All clojure.core
functions related to sequences usually understand Convex collections, making them
easy to handle. Some of those (eg. cons
, next
) have counterparts in this namespace in case the return
value must be a cell instead of a Clojure sequence.
Functions take and return cells unless specified otherwise. Predicates return JVM booleans.
Sometimes, it can be useful converting cells to Clojure data, such as unwrapping blob to byte arrays,
which is the purpose of the convex.clj
namespace.
Lastly, in the rare cases where all of this would not be enough, Java interop can be used:
https://www.javadoc.io/doc/world.convex/convex-core/latest/convex/core/data/package-summary.html
Provides an API for cells with classic `convex.core` functions such as [[conj]]. All `clojure.core` functions related to sequences usually understand Convex collections, making them easy to handle. Some of those (eg. `cons`, `next`) have counterparts in this namespace in case the return value must be a cell instead of a Clojure sequence. Functions take and return cells unless specified otherwise. Predicates return JVM booleans. Sometimes, it can be useful converting cells to Clojure data, such as unwrapping blob to byte arrays, which is the purpose of the [[convex.clj]] namespace. Lastly, in the rare cases where all of this would not be enough, Java interop can be used: https://www.javadoc.io/doc/world.convex/convex-core/latest/convex/core/data/package-summary.html
Writing, encoding CVX cells various kind of sources.
Binary is big-endian and text is UTF-8.
Also see convex.read
for the opposite idea.
Writing, encoding CVX cells various kind of sources. Binary is big-endian and text is UTF-8. Also see [[convex.read]] for the opposite idea.
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close