/jvs

Polymorphic variants of Janet's builtin get, put, each, and related utilities

BSD Zero Clause License0BSD

jvs

Polymorphic variants of Janet’s builtin get, put, each, and related utilities. They work as expected for builtin data types, but may be customized by defining :jvs/* methods on a table’s prototype.

Installation

$ jpm install https://github.com/Luewd/jvs

Usage

At minimum a custom data type should implement the :jvs/get, :jvs/put, and :jvs/next, and :jvs/length methods. If one wishes for put-in to behave differently, it would be wise to implement the :jvs/init method as well. For more reliable cloning, data types should implement :jvs/clone in a manner appropriate for the data type. To allow reversing the entries in an ordered data structure, the structure should implement :jvs/reverse and :jvs/reverse!.

The jvs interface may be implemented without depending on jvs itself, in case one wishes to be compatible with jvs without forcing the dependency on everyone.

Example implementation and usage of the jvs interface.
(import jvs)

# This is a simple prototype that implements the jvs interface by storing values
# in the :data field instead of within the primary table itself.
(def MyType
  @{:jvs/get
    (fn [self k &opt v]
      (get-in self [:data k] v))

    :jvs/put
    (fn [self k v]
      (put-in self [:data k] v))

    :jvs/next
    (fn [self &opt k]
      (next (in self :data) k))

    :jvs/length
    (fn [self] (-> (in self :data []) length))

    :jvs/clone
    (fn [self]
      (def clone (table/clone self))
      (update clone :data |(-?> $ table/clone)))})

# Create an instance of a table with the above prototype.
(def custom (table/setproto @{} MyType))

# The custom tables store values within the :data field.
(jvs/put custom :foo "bar")
(jvs/put custom :bar "baz")

# Create a normal table with no special properties.
(def tbl @{})

# When presented with a normal table, jvs/put falls back to the builtin put
# function instead of using a custom implementation.
(jvs/put tbl :foo "bar")

# The iteration works as expected, using :jvs/next and :jvs/get for custom data
# types, and the builtin next and get functions for builtin data types.
(jvs/eachp kv tbl (pp kv))
(jvs/eachp kv custom (pp kv))

# Cloning the table works as expected: the data field is itself cloned when it
# would otherwise be assigned to to the new table by reference.
(assert (not= (in custom :data)
              (in (jvs/clone custom) :data)))

License

jvs is made freely available under the terms of the BSD 0-Clause License. Third-party contributions shall be licensed under the same terms unless explicitly stated otherwise.