Tendrils and SporesΒΆ

Tendrils are what defines the inputs/outputs/parameters of any cell. They are a mapping from a string to the matching tendril. So what is a tendril then ? Well, it is a container that holdes the input/output/parameter in a type-agnostic way (like a boost::any) to allow for static introspection and Python interaction.

We have seen some code that uses tendrils to extract the information at runtime but there are other ways of getting the data. Here we will show three different ways to get the data, but you will most likely always use the last one. The first method is the most convenient to write but the other methods can also have their use case (usually for lower level tendril manipulation).

We have seen how to use tendrils with a runtime registration:

#include <ecto/ecto.hpp>

using ecto::tendrils;
namespace tutorial
{
  struct Add
  {
    static void
    declare_io(const tendrils& /*params*/, tendrils& in, tendrils& out)
    {
      in.declare<int>("a", "1st operand.").required(true);
      in.declare<int>("b", "2nd operand.").required(true);
      out.declare<int>("output", "Result of a + b.");
    }

    int
    process(const tendrils& in, const tendrils& out)
    {
      out.get<int>("output") = in.get<int>("a") + in.get<int>("b");
      return ecto::OK;
    }
  };
}

ECTO_CELL(tutorial, tutorial::Add, "Add", "Adds two integers together.");

In an effort to save duplicate declaration, you may register a member spore at tendril declaration time. A spore is basically a typed wrapper around a tendril that behaves just like a pointer.

#include <ecto/ecto.hpp>

using ecto::tendrils;
namespace tutorial
{
  struct Add
  {
    static void
    declare_io(const tendrils& /*params*/, tendrils& in, tendrils& out)
    {
      in.declare<int>("a", "1st operand.").required(true);
      in.declare<int>("b", "2nd operand.").required(true);
      out.declare<int>("output", "Result of a + b.");
    }

    void configure(const tendrils& p, const tendrils& i, const tendrils& o)
    {
      output_ = o["output"];
      a_ = i["a"];
      b_ = i["b"];
    }

    int
    process(const tendrils& in, const tendrils& out)
    {
      *output_ = (*a_ + *b_);
      return ecto::OK;
    }
  };
  ecto::spore<double> output_, a_, b_;
}

ECTO_CELL(tutorial, tutorial::Add, "Add", "Adds two integers together.");

And you can actually register a spore to a tendril when you’re declaring it, making things even shorter:

#include <ecto/ecto.hpp>

using ecto::tendrils;
namespace tutorial
{
  struct Add
  {
    static void
    declare_io(const tendrils& /*params*/, tendrils& in, tendrils& out)
    {
      in.declare(&Add::a_, "a", "1st operand.").required(true);
      in.declare(&Add::b_, "b", "2nd operand.").required(true);
      out.declare(&Add::output_, "output", "Result of a + b.");
    }

    int
    process(const tendrils& in, const tendrils& out)
    {
      *output_ = (*a_ + *b_);
      return ecto::OK;
    }
  };
  ecto::spore<double> output_, a_, b_;
}

ECTO_CELL(tutorial, tutorial::Add, "Add", "Adds two integers together.");