Provide xod/core/buffer?


#1

I’ve now seen several libraries that want to read/write buffers (I2C, Neopixel, for example): the buffers are byte [].

In my libraries, I could provide a [custom-type](https://xod.io/docs/guide/custom-types/), but then it would be specific to a particular library. I’ve avoided implementing patches for this reason.

I think it is common enough, and important enough, to warrant adding to core. XOD
currently lacks static allocation/initialization I think, so it would use the heap (alloc/new).

The obvious buffer should just be of type byte []. I have not considered other buffer types!

Patches:

  • buffer(number-of-bytes) -> buffer-object of type xod/core/byte-buffer
    • Should the buffer-object carry it’s allocated-size with it?
    • Is there a “smart” buffer type in std-c+±lib or boost or somewhere popular?
  • The implicit x-input and x-output patches
  • The specializers for it: defer, gate, if-else.
  • The specializer equal which tests the buffer-objects for addresses for equality
  • set-byte(buffer, int i, byte value) sets buffer[i]=value
  • read-byte(buffer, int i) -> byte value gets a byte at buffer[i]

Typical patches that use this type would take 2 inputs: the buffer-object and a byte-count. The byte-count for some action (read-i2c-bytes) may be different from the allocated size, of course. In the spirit of being more robust than C, we should perhaps include the allocated-size in the buffer-object and check against the requested read/write size!


#2

I see. The feature you’re talking about is arrays/lists/vectors/sequences (no matter how we call them) which are quite fundamental to be supported at the core level of the XOD language for any types. XOD lacks this feature yet. Almost lacks: there is the List<T> type in the C++ API which implements lazy sequences, but there’s no integration with it at the visual part of XOD. This yet to be done.

Your proposal may work well in some cases but in general, I see some danger with it. It involves data mutation which is a source of many bugs in programs. Consider:

   A
 /   \
 B    C
 |
 D

Let’s imagine all these nodes are passing a byte buffer around. And somewhere deep inside D there’s a set-byte node. When it’s get triggered the observable data changes for C as well which might be very surprising and confusing because visually it depends on the effects of A only. Furthermore, C won’t even notice the change after D’s update until it is evaluated for other reasons.

A “proper” solution might be passing around immutable buffer references which is allocated and owned by a single entity (A) plus a changeset that allows to “change” the upstream buffer and pass it down without actually overwriting the master data. This is exactly what List<T> with its various ListView<T> do.

I can’t promise the implementation of the system soon. Meanwhile, your proposal can work fine. Maybe, it is a good idea to encapsulate all necessary in a single regular library. Then the auto-generated libs can simply use it. From the users perspective, that should work fine because once he installs a library (wrapper) all dependencies (awgrover/byte-buffer) will install automatically.


Char buffer library